diff --git a/public/Images/Nutrition.svg b/public/Images/Nutrition.svg new file mode 100644 index 00000000..e84cd80d --- /dev/null +++ b/public/Images/Nutrition.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/components/Cards/Card.tsx b/src/components/Cards/Card.tsx index 9f03a016..d56c3704 100644 --- a/src/components/Cards/Card.tsx +++ b/src/components/Cards/Card.tsx @@ -1,27 +1,44 @@ 'use client'; -import { Card, CardBody, CardHeader, Image } from '@nextui-org/react'; +import { Card, CardBody, Image } from '@nextui-org/react'; +import React from 'react'; import { v4 as uuid } from 'uuid'; import { CardProps } from '@/domain/props/CardProps'; export default function CustomCard({ title, content }: CardProps) { return ( - - -

{title}

-
- -
+ + +
{content.map((item) => ( -
- {item.svgIcon ? ( -
{item.svgIcon}
- ) : ( - {item.altText} +
+ {item.svgIcon &&
{item.svgIcon}
} + {!item.svgIcon && item.imageSrc && ( + {item.altText + )} +
+ {title &&

{title}

} + {item.text &&

{item.text}

} + {item.value && ( +

+ {typeof item.value === 'number' ? `${item.value.toFixed(2)} M` : item.value || 'N/A'} +

+ )} +
+ {item.changeValues && ( +
+ {item.changeValues.map((delta) => ( +
+ {delta.altText} +
+

{delta.text}

+

{delta.timeText}

+
+
+ ))} +
)} -

{item.text}

- {item.timeText &&

{item.timeText}

}
))}
diff --git a/src/components/Map/FcsAccordion.tsx b/src/components/Map/FcsAccordion.tsx deleted file mode 100644 index b7a32e8a..00000000 --- a/src/components/Map/FcsAccordion.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import { Spacer } from '@nextui-org/react'; - -import FcsAccordionProps from '@/domain/props/FcsAccordionProps'; -import { FcsAccordionOperations } from '@/operations/map/FcsAccordionOperations'; -import { cardsWrapperClass } from '@/utils/primitives'; - -import { ReactComponent as FoodConsumption } from '../../../public/Images/FoodConsumption.svg'; -import { ReactComponent as Import } from '../../../public/Images/Import.svg'; -import { ReactComponent as Population } from '../../../public/Images/Population.svg'; -import AccordionContainer from '../Accordions/AccordionContainer'; -import CustomCard from '../Cards/Card'; -import { LineChart } from '../Charts/LineChart'; -import CustomInfoCircle from '../CustomInfoCircle/CustomInfoCircle'; - -export default function FcsAccordion({ countryData, loading, countryIso3Data, countryName }: FcsAccordionProps) { - const deltaOneMonth = countryData?.fcsMinus1 ? countryData.fcs - countryData.fcsMinus1 : null; - const deltaThreeMonth = countryData?.fcsMinus3 ? countryData.fcs - countryData.fcsMinus3 : null; - const fcsChartData = FcsAccordionOperations.getFcsChartData(countryData); - const rcsiChartData = FcsAccordionOperations.getRcsiChartData(countryData); - const currencyExchangeChartData = FcsAccordionOperations.getCurrencyExchangeChartData(countryIso3Data); - const balanceOfTradeChartData = FcsAccordionOperations.getBalanceOfTradeChartData(countryIso3Data); - const headlineAndFoodInflationChartData = - FcsAccordionOperations.getHeadlineAndFoodInflationChartData(countryIso3Data); - return ( -
- , - popoverInfo: FcsAccordionOperations.getFoodSecutriyPopoverInfo(), - content: ( -
- , - text: countryData?.population ? `${countryData.population.toFixed(2)} M` : 'N/A', - altText: 'Population Icon', - }, - ]} - /> - , - text: countryData?.fcs ? `${countryData.fcs.toFixed(2)} M` : 'N/A', - altText: 'Food Consumption Icon', - }, - { - imageSrc: deltaOneMonth && deltaOneMonth > 0 ? '/Images/ArrowUp.svg' : '/Images/ArrowDown.svg', - text: deltaOneMonth ? `${deltaOneMonth.toFixed(2)} M` : 'N/A', - timeText: '1 Month ago', - altText: 'Icon', - }, - { - imageSrc: - deltaThreeMonth && deltaThreeMonth > 0 ? '/Images/ArrowUp.svg' : '/Images/ArrowDown.svg', - text: deltaThreeMonth ? `${deltaThreeMonth.toFixed(2)} M` : 'N/A', - timeText: '3 Month ago', - altText: 'Other Icon', - }, - ]} - /> -
- ), - }, - { - title: 'Food Security Trends', - infoIcon: , - popoverInfo: FcsAccordionOperations.getFoodSecutriyTrendsPopoverInfo(), - content: ( -
- {fcsChartData ? ( - - ) : ( -

No data about insufficient food consumption

- )} - - {rcsiChartData ? ( - - ) : ( -

No data about crisis or above crisis food-based coping

- )} -
- ), - }, - { - title: 'Macro-economic', - infoIcon: , - popoverInfo: FcsAccordionOperations.getMacroEconomicPopoverInfo(), - content: ( -
- , - text: countryData?.importDependency - ? `${countryData.importDependency.toFixed(1)}% of Cereals` - : 'N/A', - altText: 'Import Dependency Icon', - }, - ]} - /> -
- ), - }, - { - title: 'Currency Exchange', - infoIcon: , - popoverInfo: FcsAccordionOperations.getCurrencyExchangePopoverInfo(), - content: ( -
- {currencyExchangeChartData ? ( - - ) : ( -

No data about currency exchange

- )} -
- ), - }, - { - title: 'Balance of Trade', - infoIcon: , - popoverInfo: FcsAccordionOperations.getBalanceOfTradePopoverInfo(), - content: ( -
- {balanceOfTradeChartData ? ( - - ) : ( -

No data about balance of trade

- )} -
- ), - }, - { - title: 'Headline and food inflation', - infoIcon: , - popoverInfo: FcsAccordionOperations.getHeadlineAndFoodInflationPopoverInfo(), - content: ( -
- {headlineAndFoodInflationChartData ? ( - - ) : ( -

No data about headline and food inflation

- )} -
- ), - }, - ]} - /> -
- ); -} diff --git a/src/components/Map/FcsMap/FcsAccordion.tsx b/src/components/Map/FcsMap/FcsAccordion.tsx new file mode 100644 index 00000000..a36cfce5 --- /dev/null +++ b/src/components/Map/FcsMap/FcsAccordion.tsx @@ -0,0 +1,47 @@ +import FcsAccordionProps from '@/domain/props/FcsAccordionProps'; +import { FcsFoodSecurityOperations } from '@/operations/map/FcsFoodSecurityOperations'; +import { FcsMacroEconomicOperations } from '@/operations/map/FcsMacroEconomicOperations'; +import { useMediaQuery } from '@/utils/resolution.ts'; + +import AccordionContainer from '../../Accordions/AccordionContainer'; + +export default function FcsAccordion({ countryData, loading, countryIso3Data, countryName }: FcsAccordionProps) { + const isMobile = useMediaQuery('(max-width: 700px)'); + const foodSecurityAccordionItems = FcsFoodSecurityOperations.getFcsFoodSecurityAccordionItems( + countryData, + countryIso3Data + ); + const macroEconomicAccordionItems = FcsMacroEconomicOperations.getMacroEconomicAccordionItems( + countryData, + countryIso3Data + ); + + return isMobile ? ( +
+ +
+ ) : ( + <> +
+ +
+
+ +
+ + ); +} diff --git a/src/components/Map/FcsChoropleth.tsx b/src/components/Map/FcsMap/FcsChoropleth.tsx similarity index 96% rename from src/components/Map/FcsChoropleth.tsx rename to src/components/Map/FcsMap/FcsChoropleth.tsx index 0f49d268..3f36570f 100644 --- a/src/components/Map/FcsChoropleth.tsx +++ b/src/components/Map/FcsMap/FcsChoropleth.tsx @@ -11,8 +11,8 @@ import FcsChoroplethProps from '@/domain/props/FcsChoroplethProps'; import FcsChoroplethOperations from '@/operations/map/FcsChoroplethOperations'; import { MapOperations } from '@/operations/map/MapOperations'; -import AccordionModalSkeleton from '../Accordions/AccordionModalSkeleton'; -import CountryLoadingLayer from './CountryLoading'; +import AccordionModalSkeleton from '../../Accordions/AccordionModalSkeleton'; +import CountryLoadingLayer from '../CountryLoading'; import FscCountryChoropleth from './FcsCountryChoropleth'; export default function FcsChoropleth({ diff --git a/src/components/Map/FcsCountryChoropleth.tsx b/src/components/Map/FcsMap/FcsCountryChoropleth.tsx similarity index 100% rename from src/components/Map/FcsCountryChoropleth.tsx rename to src/components/Map/FcsMap/FcsCountryChoropleth.tsx diff --git a/src/components/Map/FcsRegionTooltip.tsx b/src/components/Map/FcsMap/FcsRegionTooltip.tsx similarity index 97% rename from src/components/Map/FcsRegionTooltip.tsx rename to src/components/Map/FcsMap/FcsRegionTooltip.tsx index 3ad1ad99..67017b26 100644 --- a/src/components/Map/FcsRegionTooltip.tsx +++ b/src/components/Map/FcsMap/FcsRegionTooltip.tsx @@ -3,7 +3,7 @@ import { Feature, GeoJsonProperties, Geometry } from 'geojson'; import { FcsRegionTooltipOperations } from '@/operations/map/FcsRegionTooltipOperations'; import { formatToMillion } from '@/utils/formatting'; -import { LineChart } from '../Charts/LineChart'; +import { LineChart } from '../../Charts/LineChart'; interface FcsRegionTooltipProps { feature: Feature; diff --git a/src/components/Map/IpcMap/IpcAccordion.tsx b/src/components/Map/IpcMap/IpcAccordion.tsx index 57ec55e6..f1e8a121 100644 --- a/src/components/Map/IpcMap/IpcAccordion.tsx +++ b/src/components/Map/IpcMap/IpcAccordion.tsx @@ -1,71 +1,29 @@ import AccordionContainer from '@/components/Accordions/AccordionContainer'; -import CustomCard from '@/components/Cards/Card'; -import CustomInfoCircle from '@/components/CustomInfoCircle/CustomInfoCircle'; import IpcAccordionProps from '@/domain/props/IpcAccordionProps'; -import { FcsAccordionOperations } from '@/operations/map/FcsAccordionOperations'; -import { cardsWrapperClass } from '@/utils/primitives'; +import { IpcFoodSecurityAccordionOperations } from '@/operations/map/IpcFoodSecurityOperations'; +import { useMediaQuery } from '@/utils/resolution.ts'; -import { ReactComponent as FoodConsumption } from '../../../../public/Images/FoodConsumption.svg'; -import { ReactComponent as Population } from '../../../../public/Images/Population.svg'; - -export default function IpcAccordion({ countryData, countryName }: IpcAccordionProps) { +export default function IpcAccordion({ countryData, countryName, countryIso3Data }: IpcAccordionProps) { const deltaOneMonth = countryData?.fcsMinus1 ? countryData.fcs - countryData.fcsMinus1 : null; const deltaThreeMonth = countryData?.fcsMinus3 ? countryData.fcs - countryData.fcsMinus3 : null; - const hasNoData: boolean = - !countryData || !countryData.population || !countryData.fcs || !deltaOneMonth || !deltaThreeMonth; + + const foodSecurityAccordionItems = IpcFoodSecurityAccordionOperations.getFoodSecurityAccordionItems( + countryData, + deltaOneMonth, + deltaThreeMonth + ); + const nutrititonAccordionItems = IpcFoodSecurityAccordionOperations.getNutritionAccordionItems(countryIso3Data); + const isMobile = useMediaQuery('(max-width: 700px)'); return (
, - popoverInfo: FcsAccordionOperations.getFoodSecutriyPopoverInfo(), - content: !hasNoData ? ( -
- , - text: countryData?.population ? `${countryData?.population.toFixed(2)} M` : 'N/A', - altText: 'Population Icon', - }, - ]} - /> - , - text: countryData?.fcs ? `${countryData?.fcs.toFixed(2)} M` : 'N/A', - altText: 'Food Consumption Icon', - }, - { - imageSrc: deltaOneMonth && deltaOneMonth > 0 ? '/Images/ArrowUp.svg' : '/Images/ArrowDown.svg', - text: deltaOneMonth ? `${deltaOneMonth.toFixed(2)} M` : 'N/A', - timeText: '1 Months ago', - altText: 'Other Icon', - }, - { - imageSrc: - deltaThreeMonth && deltaThreeMonth > 0 ? '/Images/ArrowUp.svg' : '/Images/ArrowDown.svg', - text: deltaThreeMonth ? `${deltaThreeMonth.toFixed(2)} M` : 'N/A', - timeText: '3 Month ago', - altText: 'Other Icon', - }, - ]} - /> -
- ) : ( -

No data about food security

- ), - }, - ]} + items={[foodSecurityAccordionItems, nutrititonAccordionItems]} + multipleSelectionMode={!isMobile} + expandAll={!isMobile} />
); diff --git a/src/components/Map/IpcMap/IpcChoropleth.tsx b/src/components/Map/IpcMap/IpcChoropleth.tsx index 5a9a553c..2ef63dfe 100644 --- a/src/components/Map/IpcMap/IpcChoropleth.tsx +++ b/src/components/Map/IpcMap/IpcChoropleth.tsx @@ -10,7 +10,13 @@ import { IpcChoroplethProps } from '@/domain/props/IpcChoroplethProps'; import IpcCountryChoropleth from './IpcCountryChoropleth'; import IpcGlobalChoropleth from './IpcGlobalChoropleth'; -function IpcChoropleth({ countries, countryData, ipcRegionData, selectedCountryName }: IpcChoroplethProps) { +function IpcChoropleth({ + countries, + countryData, + ipcRegionData, + selectedCountryName, + countryIso3Data, +}: IpcChoroplethProps) { const { data: ipcData } = useIpcQuery(true); const { selectedCountryId, setSelectedCountryId } = useSelectedCountryId(); @@ -45,6 +51,7 @@ function IpcChoropleth({ countries, countryData, ipcRegionData, selectedCountryN regionIpcData={ipcRegionData} countryData={countryData} countryName={selectedCountryName} + countryIso3Data={countryIso3Data} /> )} diff --git a/src/components/Map/IpcMap/IpcCountryChoropleth.tsx b/src/components/Map/IpcMap/IpcCountryChoropleth.tsx index 77284d9b..f342ce09 100644 --- a/src/components/Map/IpcMap/IpcCountryChoropleth.tsx +++ b/src/components/Map/IpcMap/IpcCountryChoropleth.tsx @@ -7,13 +7,13 @@ import { IpcChoroplethOperations } from '@/operations/map/IpcChoroplethOperation import IpcAccordion from './IpcAccordion'; -function IpcCountryChoropleth({ regionIpcData, countryData, countryName }: IpcCountryChoroplethProps) { +function IpcCountryChoropleth({ regionIpcData, countryData, countryName, countryIso3Data }: IpcCountryChoroplethProps) { const handleCountryFeature = (feature: Feature, layer: L.Layer) => { IpcChoroplethOperations.attachEventsRegion(feature, layer); }; return ( <> - + )} diff --git a/src/components/Map/NutritionAccordion.tsx b/src/components/Map/NutritionMap/NutritionAccordion.tsx similarity index 100% rename from src/components/Map/NutritionAccordion.tsx rename to src/components/Map/NutritionMap/NutritionAccordion.tsx diff --git a/src/components/Map/NutritionChoropleth.tsx b/src/components/Map/NutritionMap/NutritionChoropleth.tsx similarity index 96% rename from src/components/Map/NutritionChoropleth.tsx rename to src/components/Map/NutritionMap/NutritionChoropleth.tsx index f74563f9..977d6c39 100644 --- a/src/components/Map/NutritionChoropleth.tsx +++ b/src/components/Map/NutritionMap/NutritionChoropleth.tsx @@ -12,8 +12,8 @@ import NutritionChoroplethProps from '@/domain/props/NutritionChoroplethProps'; import { MapOperations } from '@/operations/map/MapOperations'; import NutritionChoroplethOperations from '@/operations/map/NutritionChoroplethOperations'; -import AccordionModalSkeleton from '../Accordions/AccordionModalSkeleton'; -import CountryLoadingLayer from './CountryLoading'; +import AccordionModalSkeleton from '../../Accordions/AccordionModalSkeleton'; +import CountryLoadingLayer from '../CountryLoading'; import NutritionStateChoropleth from './NutritionStateChoropleth'; export default function NutritionChoropleth({ diff --git a/src/components/Map/NutritionRegionTooltip.tsx b/src/components/Map/NutritionMap/NutritionRegionTooltip.tsx similarity index 100% rename from src/components/Map/NutritionRegionTooltip.tsx rename to src/components/Map/NutritionMap/NutritionRegionTooltip.tsx diff --git a/src/components/Map/NutritionStateChoropleth.tsx b/src/components/Map/NutritionMap/NutritionStateChoropleth.tsx similarity index 100% rename from src/components/Map/NutritionStateChoropleth.tsx rename to src/components/Map/NutritionMap/NutritionStateChoropleth.tsx diff --git a/src/domain/entities/cards/CardContent.ts b/src/domain/entities/cards/CardContent.ts index 091f7fce..a593d4a9 100644 --- a/src/domain/entities/cards/CardContent.ts +++ b/src/domain/entities/cards/CardContent.ts @@ -1,8 +1,16 @@ export interface CardContent { imageSrc?: string; svgIcon?: React.ReactNode; - text?: string; + text?: React.ReactNode; + value?: string | number; content?: React.ReactNode; timeText?: string; altText?: string; + changeValues?: { + imageSrc: string; + text: string; + timeText: string; + altText: string; + }[]; + textClass?: string; } diff --git a/src/domain/props/CardProps.tsx b/src/domain/props/CardProps.tsx index 395c2dbf..7c3915a2 100644 --- a/src/domain/props/CardProps.tsx +++ b/src/domain/props/CardProps.tsx @@ -1,6 +1,6 @@ import { CardContent } from '../entities/cards/CardContent'; export interface CardProps { - title: string; + title?: string; content: CardContent[]; } diff --git a/src/domain/props/FcsAccordionProps.tsx b/src/domain/props/FcsAccordionProps.tsx index d17756bf..fa9e49c8 100644 --- a/src/domain/props/FcsAccordionProps.tsx +++ b/src/domain/props/FcsAccordionProps.tsx @@ -4,6 +4,6 @@ import { CountryIso3Data } from '../entities/country/CountryIso3Data'; export default interface FcsAccordionProps { countryData?: CountryData; countryIso3Data?: CountryIso3Data; - loading: boolean; + loading?: boolean; countryName?: string; } diff --git a/src/domain/props/IpcAccordionProps.tsx b/src/domain/props/IpcAccordionProps.tsx index e60f69a7..78e96cf9 100644 --- a/src/domain/props/IpcAccordionProps.tsx +++ b/src/domain/props/IpcAccordionProps.tsx @@ -1,6 +1,8 @@ import { CountryData } from '../entities/country/CountryData'; +import { CountryIso3Data } from '../entities/country/CountryIso3Data'; export default interface IpcAccordionProps { countryData: CountryData | undefined; countryName?: string; + countryIso3Data: CountryIso3Data | undefined; } diff --git a/src/domain/props/IpcChoroplethProps.tsx b/src/domain/props/IpcChoroplethProps.tsx index 28728fa1..8f87d388 100644 --- a/src/domain/props/IpcChoroplethProps.tsx +++ b/src/domain/props/IpcChoroplethProps.tsx @@ -3,10 +3,13 @@ import { FeatureCollection, GeoJsonProperties, Geometry } from 'geojson'; import { CountryData } from '@/domain/entities/country/CountryData.ts'; import { CountryMapDataWrapper } from '@/domain/entities/country/CountryMapData'; +import { CountryIso3Data } from '../entities/country/CountryIso3Data'; + export interface IpcChoroplethProps { countries: CountryMapDataWrapper; handleBackButtonClick?: () => void; countryData?: CountryData; ipcRegionData?: FeatureCollection; selectedCountryName?: string; + countryIso3Data: CountryIso3Data | undefined; } diff --git a/src/domain/props/IpcCountryChoroplethProps.tsx b/src/domain/props/IpcCountryChoroplethProps.tsx index 4ecd7366..9b66d19b 100644 --- a/src/domain/props/IpcCountryChoroplethProps.tsx +++ b/src/domain/props/IpcCountryChoroplethProps.tsx @@ -1,9 +1,11 @@ import { FeatureCollection, GeoJsonProperties, Geometry } from 'geojson'; import { CountryData } from '../entities/country/CountryData'; +import { CountryIso3Data } from '../entities/country/CountryIso3Data'; export default interface IpcCountryChoroplethProps { regionIpcData: FeatureCollection; countryData: CountryData | undefined; countryName?: string; + countryIso3Data: CountryIso3Data | undefined; } diff --git a/src/domain/props/NutritionAccordionTextProps.tsx b/src/domain/props/NutritionAccordionTextProps.tsx new file mode 100644 index 00000000..29665514 --- /dev/null +++ b/src/domain/props/NutritionAccordionTextProps.tsx @@ -0,0 +1,4 @@ +export default interface NutritionAccordionTextProps { + nutritionValue: string; + text: string; +} diff --git a/src/operations/map/FcsAccordionOperations.tsx b/src/operations/map/FcsAccordionOperations.tsx index 7a86f439..2acf5392 100644 --- a/src/operations/map/FcsAccordionOperations.tsx +++ b/src/operations/map/FcsAccordionOperations.tsx @@ -104,6 +104,18 @@ export class FcsAccordionOperations { }; } + static getNutritionData(countryIso3Data?: CountryIso3Data) { + if (!countryIso3Data?.nutrition) { + return null; + } + + const { wasting, stunting } = countryIso3Data.nutrition; + return { + Acute: wasting, + Chronic: stunting, + }; + } + static getFoodSecutriyPopoverInfo(): ReactNode { return (
diff --git a/src/operations/map/FcsCountryChoroplethOperations.tsx b/src/operations/map/FcsCountryChoroplethOperations.tsx index fc0c22e0..dbb20ed3 100644 --- a/src/operations/map/FcsCountryChoroplethOperations.tsx +++ b/src/operations/map/FcsCountryChoroplethOperations.tsx @@ -3,7 +3,7 @@ import L from 'leaflet'; import React from 'react'; import { createRoot } from 'react-dom/client'; -import FcsRegionTooltip from '@/components/Map/FcsRegionTooltip'; +import FcsRegionTooltip from '@/components/Map/FcsMap/FcsRegionTooltip'; import { CountryMapData } from '@/domain/entities/country/CountryMapData.ts'; import { MapOperations } from '@/operations/map/MapOperations'; diff --git a/src/operations/map/FcsFoodSecurityOperations.tsx b/src/operations/map/FcsFoodSecurityOperations.tsx new file mode 100644 index 00000000..020b9c8a --- /dev/null +++ b/src/operations/map/FcsFoodSecurityOperations.tsx @@ -0,0 +1,150 @@ +import { Spacer } from '@nextui-org/react'; + +import CustomCard from '@/components/Cards/Card'; +import { LineChart } from '@/components/Charts/LineChart'; +import CustomInfoCircle from '@/components/CustomInfoCircle/CustomInfoCircle'; +import { CountryData } from '@/domain/entities/country/CountryData'; +import { CountryIso3Data } from '@/domain/entities/country/CountryIso3Data'; +import { cardsWrapperClass } from '@/utils/primitives'; + +import { ReactComponent as FoodConsumption } from '../../../public/Images/FoodConsumption.svg'; +import { ReactComponent as Nutrition } from '../../../public/Images/Nutrition.svg'; +import { ReactComponent as Population } from '../../../public/Images/Population.svg'; +import { FcsAccordionOperations } from './FcsAccordionOperations'; +import NutritionAccordionText from './NutritionAccordionText'; + +export class FcsFoodSecurityOperations { + static getFcsFoodSecurityAccordionItems( + countryData: CountryData | undefined, + countryIso3Data: CountryIso3Data | undefined + ) { + const deltaOneMonth = countryData?.fcsMinus1 ? countryData.fcs - countryData.fcsMinus1 : null; + const deltaThreeMonth = countryData?.fcsMinus3 ? countryData.fcs - countryData.fcsMinus3 : null; + const fcsChartData = FcsAccordionOperations.getFcsChartData(countryData); + const rcsiChartData = FcsAccordionOperations.getRcsiChartData(countryData); + const nutritionData = FcsAccordionOperations.getNutritionData(countryIso3Data); + return [ + { + title: 'Food Security', + infoIcon: , + popoverInfo: FcsAccordionOperations.getFoodSecutriyPopoverInfo(), + content: ( +
+ , + text: countryData?.population ? `${countryData.population.toFixed(2)} M` : 'N/A', + altText: 'Population Icon', + textClass: 'text-base', + }, + ]} + /> + , + text: 'Population with insufficient food consumption', + value: countryData?.fcs ? `${countryData.fcs.toFixed(2)} M` : 'N/A', + textClass: 'text-xs', + changeValues: [ + { + imageSrc: deltaOneMonth && deltaOneMonth > 0 ? '/Images/ArrowUp.svg' : '/Images/ArrowDown.svg', + text: deltaOneMonth ? `${deltaOneMonth.toFixed(2)} M` : 'N/A', + timeText: '1 Month ago', + altText: 'Delta Icon', + }, + { + imageSrc: + deltaThreeMonth && deltaThreeMonth > 0 ? '/Images/ArrowUp.svg' : '/Images/ArrowDown.svg', + text: deltaThreeMonth ? `${deltaThreeMonth.toFixed(2)} M` : 'N/A', + timeText: '3 Months ago', + altText: 'Delta Icon', + }, + ], + }, + ]} + /> +
+ ), + }, + { + title: 'Nutrition', + infoIcon: , + popoverInfo: FcsAccordionOperations.getFoodSecutriyPopoverInfo(), + content: + nutritionData && (nutritionData.Acute != null || nutritionData.Chronic != null) ? ( +
+ {nutritionData.Acute != null && ( + , + text: ( + + ), + }, + ]} + /> + )} + {nutritionData.Chronic != null && ( + , + text: ( + + ), + }, + ]} + /> + )} +
+ ) : ( +

No data about Nutrition is available

+ ), + }, + { + title: 'Food Security Trends', + infoIcon: , + popoverInfo: FcsAccordionOperations.getFoodSecutriyTrendsPopoverInfo(), + content: ( +
+ {fcsChartData ? ( + + ) : ( +

No data about insufficient food consumption

+ )} + + {rcsiChartData ? ( + + ) : ( +

No data about crisis or above crisis food-based coping

+ )} +
+ ), + }, + ]; + } +} diff --git a/src/operations/map/FcsMacroEconomicOperations.tsx b/src/operations/map/FcsMacroEconomicOperations.tsx new file mode 100644 index 00000000..bd4bc438 --- /dev/null +++ b/src/operations/map/FcsMacroEconomicOperations.tsx @@ -0,0 +1,88 @@ +import CustomCard from '@/components/Cards/Card'; +import { LineChart } from '@/components/Charts/LineChart'; +import CustomInfoCircle from '@/components/CustomInfoCircle/CustomInfoCircle'; +import { CountryData } from '@/domain/entities/country/CountryData'; +import { CountryIso3Data } from '@/domain/entities/country/CountryIso3Data'; +import { cardsWrapperClass } from '@/utils/primitives'; + +import { ReactComponent as Import } from '../../../public/Images/Import.svg'; +import { FcsAccordionOperations } from './FcsAccordionOperations'; + +export class FcsMacroEconomicOperations { + static getMacroEconomicAccordionItems( + countryData: CountryData | undefined, + countryIso3Data: CountryIso3Data | undefined + ) { + const currencyExchangeChartData = FcsAccordionOperations.getCurrencyExchangeChartData(countryIso3Data); + const balanceOfTradeChartData = FcsAccordionOperations.getBalanceOfTradeChartData(countryIso3Data); + const headlineAndFoodInflationChartData = + FcsAccordionOperations.getHeadlineAndFoodInflationChartData(countryIso3Data); + + return [ + { + title: 'Macroeconomic', + infoIcon: , + popoverInfo: FcsAccordionOperations.getMacroEconomicPopoverInfo(), + content: ( +
+ , + text: countryData?.importDependency + ? `${countryData.importDependency.toFixed(1)}% of Cereals` + : 'N/A', + altText: 'Import Dependency Icon', + textClass: 'text-base', + }, + ]} + /> +
+ ), + }, + { + title: 'Currency Exchange', + infoIcon: , + popoverInfo: FcsAccordionOperations.getCurrencyExchangePopoverInfo(), + content: ( +
+ {currencyExchangeChartData ? ( + + ) : ( +

No data about currency exchange

+ )} +
+ ), + }, + { + title: 'Balance of Trade', + infoIcon: , + popoverInfo: FcsAccordionOperations.getBalanceOfTradePopoverInfo(), + content: ( +
+ {balanceOfTradeChartData ? ( + + ) : ( +

No data about balance of trade

+ )} +
+ ), + }, + { + title: 'Headline and food inflation', + infoIcon: , + popoverInfo: FcsAccordionOperations.getHeadlineAndFoodInflationPopoverInfo(), + content: ( +
+ {headlineAndFoodInflationChartData ? ( + + ) : ( +

No data about headline and food inflation

+ )} +
+ ), + }, + ]; + } +} diff --git a/src/operations/map/IpcFoodSecurityOperations.tsx b/src/operations/map/IpcFoodSecurityOperations.tsx new file mode 100644 index 00000000..066b5aa0 --- /dev/null +++ b/src/operations/map/IpcFoodSecurityOperations.tsx @@ -0,0 +1,128 @@ +import React from 'react'; + +import CustomCard from '@/components/Cards/Card'; +import CustomInfoCircle from '@/components/CustomInfoCircle/CustomInfoCircle'; +import { CountryData } from '@/domain/entities/country/CountryData'; +import { CountryIso3Data } from '@/domain/entities/country/CountryIso3Data'; +import { cardsWrapperClass } from '@/utils/primitives'; + +import { ReactComponent as FoodConsumption } from '../../../public/Images/FoodConsumption.svg'; +import { ReactComponent as Nutrition } from '../../../public/Images/Nutrition.svg'; +import { ReactComponent as Population } from '../../../public/Images/Population.svg'; +import { FcsAccordionOperations } from './FcsAccordionOperations'; +import NutritionAccordionText from './NutritionAccordionText'; + +export class IpcFoodSecurityAccordionOperations { + static getFoodSecurityAccordionItems( + countryData: CountryData | undefined, + deltaOneMonth: number | null, + deltaThreeMonth: number | null + ) { + const hasNoData = + !countryData || !countryData.population || !countryData.fcs || deltaOneMonth === null || deltaThreeMonth === null; + + if (hasNoData) { + return { + title: 'Food Security', + infoIcon: , + popoverInfo: FcsAccordionOperations.getFoodSecutriyPopoverInfo(), + content:

No data about food security

, + }; + } + + return { + title: 'Food Security', + infoIcon: , + popoverInfo: FcsAccordionOperations.getFoodSecutriyPopoverInfo(), + content: ( +
+ , + text: countryData.population ? `${countryData.population.toFixed(2)} M` : 'N/A', + altText: 'Population Icon', + textClass: 'text-base', + }, + ]} + /> + , + text: 'Population with insufficient food consumption', + value: countryData.fcs ? `${countryData.fcs.toFixed(2)} M` : 'N/A', + textClass: 'text-xs', + changeValues: [ + { + imageSrc: deltaOneMonth && deltaOneMonth > 0 ? '/Images/ArrowUp.svg' : '/Images/ArrowDown.svg', + text: deltaOneMonth ? `${deltaOneMonth.toFixed(2)} M` : 'N/A', + timeText: '1 Month ago', + altText: 'Delta Icon', + }, + { + imageSrc: deltaThreeMonth && deltaThreeMonth > 0 ? '/Images/ArrowUp.svg' : '/Images/ArrowDown.svg', + text: deltaThreeMonth ? `${deltaThreeMonth.toFixed(2)} M` : 'N/A', + timeText: '3 Months ago', + altText: 'Delta Icon', + }, + ], + }, + ]} + /> +
+ ), + }; + } + + static getNutritionAccordionItems(countryIso3Data: CountryIso3Data | undefined) { + const nutritionData = FcsAccordionOperations.getNutritionData(countryIso3Data); + + if (!nutritionData || (nutritionData.Acute == null && nutritionData.Chronic == null)) { + return { + title: 'Nutrition', + infoIcon: , + content:

No data about Nutrition is available

, + }; + } + + return { + title: 'Nutrition', + infoIcon: , + content: ( +
+ {nutritionData.Acute != null && ( + , + text: ( + + ), + }, + ]} + /> + )} + {nutritionData.Chronic != null && ( + , + text: ( + + ), + }, + ]} + /> + )} +
+ ), + }; + } +} diff --git a/src/operations/map/MapOperations.tsx b/src/operations/map/MapOperations.tsx index 1aa77426..9df95f66 100644 --- a/src/operations/map/MapOperations.tsx +++ b/src/operations/map/MapOperations.tsx @@ -78,7 +78,7 @@ export class MapOperations { setCountryData(newCountryData); } - if (selectedMapType === GlobalInsight.FOOD) { + if (selectedMapType === GlobalInsight.FOOD || selectedMapType === GlobalInsight.IPC) { const newCountryIso3Data = await countryRepository.getCountryIso3Data(selectedCountryData.properties.iso3); setCountryIso3Data(newCountryIso3Data); } diff --git a/src/operations/map/NutritionAccordionText.tsx b/src/operations/map/NutritionAccordionText.tsx new file mode 100644 index 00000000..ad6a6396 --- /dev/null +++ b/src/operations/map/NutritionAccordionText.tsx @@ -0,0 +1,11 @@ +import NutritionAccordionTextProps from '@/domain/props/NutritionAccordionTextProps'; + +function NutritionAccordionText({ nutritionValue, text }: NutritionAccordionTextProps) { + return ( + <> + {nutritionValue} + {text} + + ); +} +export default NutritionAccordionText; diff --git a/src/operations/map/NutritionStateChoroplethOperations.tsx b/src/operations/map/NutritionStateChoroplethOperations.tsx index 7ee50e08..77e68635 100644 --- a/src/operations/map/NutritionStateChoroplethOperations.tsx +++ b/src/operations/map/NutritionStateChoroplethOperations.tsx @@ -2,7 +2,7 @@ import { Feature } from 'geojson'; import { PathOptions } from 'leaflet'; import { createRoot } from 'react-dom/client'; -import NutritionRegionTooltip from '@/components/Map/NutritionRegionTooltip'; +import NutritionRegionTooltip from '@/components/Map/NutritionMap/NutritionRegionTooltip'; import { NUTRIENT_LABELS } from '@/domain/constant/map/NutritionChoropleth.ts'; import { LayerWithFeature } from '@/domain/entities/map/LayerWithFeature.ts'; import { Nutrition } from '@/domain/entities/region/RegionNutritionProperties.ts'; diff --git a/src/utils/primitives.ts b/src/utils/primitives.ts index 48ed96a9..95e98dcc 100644 --- a/src/utils/primitives.ts +++ b/src/utils/primitives.ts @@ -44,4 +44,4 @@ export const subtitle = tv({ }, }); -export const cardsWrapperClass = 'cards-wrapper flex flex-row gap-4 justify-center flex-wrap'; +export const cardsWrapperClass = 'cards-wrapper flex flex-row gap-1 justify-center flex-wrap'; diff --git a/yarn.lock b/yarn.lock index 1a2c8f76..233f196a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1390,6 +1390,11 @@ resolved "https://registry.yarnpkg.com/@next/env/-/env-13.5.7.tgz#5006f4460a7fa598a03e1c2aa4e59e45c71082d3" integrity sha512-uVuRqoj28Ys/AI/5gVEgRAISd0KWI0HRjOO1CTpNgmX3ZsHb5mdn14Y59yk0IxizXdo7ZjsI2S7qbWnO+GNBcA== +"@next/env@^13.4.3": + version "13.5.7" + resolved "https://registry.yarnpkg.com/@next/env/-/env-13.5.7.tgz#5006f4460a7fa598a03e1c2aa4e59e45c71082d3" + integrity sha512-uVuRqoj28Ys/AI/5gVEgRAISd0KWI0HRjOO1CTpNgmX3ZsHb5mdn14Y59yk0IxizXdo7ZjsI2S7qbWnO+GNBcA== + "@next/eslint-plugin-next@15.0.1": version "15.0.1" resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-15.0.1.tgz#76117d88aadc52f6e04b1892d44654d05468d53c"