From 794514aef93d759cdeef9ace55ad3a35ee764118 Mon Sep 17 00:00:00 2001 From: balagurova Date: Fri, 12 Jul 2024 21:34:09 +0300 Subject: [PATCH] Change structure of Constants --- src/App.tsx | 117 +++++------ src/Components/Cards.tsx | 108 ++++------- src/Components/Constants.tsx | 182 ++++++++---------- .../Graphs/Maps/ChoroplethMap/index.tsx | 8 +- src/Components/Header.tsx | 48 +++-- src/Components/Summary.tsx | 96 --------- 6 files changed, 206 insertions(+), 353 deletions(-) delete mode 100644 src/Components/Summary.tsx diff --git a/src/App.tsx b/src/App.tsx index 73776e0..efe50aa 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,7 +12,7 @@ import { Segmented } from 'antd'; import { ChoroplethMap } from './Components/Graphs/Maps/ChoroplethMap'; import Header from './Components/Header'; import FilterCountryGroup from './Components/Filter'; -import { PROGRAMMES, SPECIFIED_PROGRAMMES } from './Components/Constants'; +import { PROGRAMMES } from './Components/Constants'; import { ProgrammeProvider, useProgramme } from './Components/ProgrammeContext'; import CheckboxGroup from './Components/CheckboxGroup'; import { ChoroplethMapDataType } from './Types'; @@ -58,23 +58,29 @@ function AppContent() { setLdcCountries(ldc); const transformedData = loadedData.map((item: any) => { - const allProgrammesSum = SPECIFIED_PROGRAMMES.reduce( - (sum, program) => sum + (parseInt(item[program.value], 10) || 0), - 0, - ); + const allProgrammesSum = + PROGRAMMES[0].subprogrammes?.reduce( + (sum, program) => sum + (parseInt(item[program.value], 10) || 0), + 0, + ) || 0; - const publicFinanceSum = [ - 'public_tax', - 'public_debt', - 'public_budget', - 'public_insurance', - ].reduce((sum, key) => sum + (parseInt(item[key], 10) || 0), 0); + const publicProgramme = PROGRAMMES[0].subprogrammes?.find( + p => p.value === 'public', + ); + const publicFinanceSum = + publicProgramme?.subprogrammes?.reduce( + (sum, sub) => sum + (parseInt(item[sub.value], 10) || 0), + 0, + ) || 0; - const privateCapitalSum = [ - 'private_pipelines', - 'private_impact', - 'private_environment', - ].reduce((sum, key) => sum + (parseInt(item[key], 10) || 0), 0); + const privateProgramme = PROGRAMMES[0].subprogrammes?.find( + p => p.value === 'private', + ); + const privateCapitalSum = + privateProgramme?.subprogrammes?.reduce( + (sum, sub) => sum + (parseInt(item[sub.value], 10) || 0), + 0, + ) || 0; return { ...item, @@ -90,8 +96,16 @@ function AppContent() { const handleSegmentChange = useCallback( (value: string | number) => { - const programme = PROGRAMMES.find(p => p.value === value); - if (programme) setCurrentProgramme(programme); + const allProgrammesOption = PROGRAMMES.find( + p => p.value === 'all_programmes', + ); + const programme = + allProgrammesOption?.subprogrammes?.find(p => p.value === value) || + PROGRAMMES.find(p => p.value === value); + + if (programme) { + setCurrentProgramme(programme); + } }, [setCurrentProgramme], ); @@ -140,32 +154,21 @@ function AppContent() { let value = 0; if (programme === 'all_programmes') { - if (selectedCheckboxes.includes('public')) { - const publicSum = [ - 'public_budget', - 'public_tax', - 'public_debt', - 'public_insurance', - ].reduce((sum, sub) => sum + (parseInt(item[sub], 10) || 0), 0); - value += publicSum; - } - - if (selectedCheckboxes.includes('private')) { - const privateSum = [ - 'private_pipelines', - 'private_impact', - 'private_environment', - ].reduce((sum, sub) => sum + (parseInt(item[sub], 10) || 0), 0); - value += privateSum; - } - - if (selectedCheckboxes.includes('frameworks')) { - value += parseInt(item.frameworks, 10) || 0; - } - - if (selectedCheckboxes.includes('biofin')) { - value += parseInt(item.biofin, 10) || 0; - } + const mainProgrammes = PROGRAMMES[0].subprogrammes || []; + mainProgrammes.forEach(mainProgramme => { + if (selectedCheckboxes.includes(mainProgramme.value)) { + value += + mainProgramme.subprogrammes?.reduce( + (sum, sub) => sum + (parseInt(item[sub.value], 10) || 0), + 0, + ) || 0; + } + }); + } else if (currentProgramme.subprogrammes) { + value = currentProgramme.subprogrammes.reduce( + (sum, sub) => sum + (parseInt(item[sub.value], 10) || 0), + 0, + ); } else { value = parseFloat(item[programme]); } @@ -177,7 +180,7 @@ function AppContent() { }; }); }, - [filterData, selectedCheckboxes], + [filterData, selectedCheckboxes, currentProgramme], ); const filteredAndTransformedData = transformData( @@ -188,32 +191,12 @@ function AppContent() { const filteredDataForCards = filterData(data, selectedRadio); - const subcategoriesToShow = - currentProgramme.value === 'public' - ? SPECIFIED_PROGRAMMES.filter(program => - [ - 'public_budget', - 'public_tax', - 'public_debt', - 'public_insurance', - ].includes(program.value), - ) - : currentProgramme.value === 'private' - ? SPECIFIED_PROGRAMMES.filter(program => - [ - 'private_pipelines', - 'private_impact', - 'private_environment', - ].includes(program.value), - ) - : currentProgramme.value === 'all_programmes' - ? PROGRAMMES.filter(program => program.value !== 'all_programmes') - : []; + const subcategoriesToShow = currentProgramme.subprogrammes || []; useEffect(() => { const subcategories = subcategoriesToShow.map(sub => sub.value); setSelectedCheckboxes(subcategories); - }, [currentProgramme]); + }, [currentProgramme, subcategoriesToShow]); return (
{ - if (currentProgramme.value === 'public') { - return SPECIFIED_PROGRAMMES.filter(program => - [ - 'public_budget', - 'public_tax', - 'public_debt', - 'public_insurance', - ].includes(program.value), - ); - } - if (currentProgramme.value === 'private') { - return SPECIFIED_PROGRAMMES.filter(program => - ['private_pipelines', 'private_impact', 'private_environment'].includes( - program.value, - ), - ); - } - if (currentProgramme.value === 'all_programmes') { - return PROGRAMMES.filter(program => - ['public', 'private', 'frameworks', 'biofin'].includes(program.value), - ); - } - return []; - }, [currentProgramme.value]); - const getCountryName = (iso: string) => { const country = taxonomy.find(item => item['Alpha-3 code'] === iso); return country ? country['Country or Area'] : iso; @@ -90,53 +64,41 @@ function Cards(props: Props) { const getProgramTags = (item: any) => { if (currentProgramme.value === 'all_programmes') { - const tags: { value: string; short: string; color: string }[] = []; - - if ( - ['public_budget', 'public_tax', 'public_debt', 'public_insurance'].some( - sub => item[sub] === '1', - ) - ) { - tags.push({ - value: 'public', - short: 'Public finance', - color: '#5DD4F0', - }); - } - if ( - ['private_pipelines', 'private_impact', 'private_environment'].some( - sub => item[sub] === '1', - ) - ) { - tags.push({ - value: 'private', - short: 'Private finance', - color: '#02A38A', - }); - } - if (item.frameworks === '1') { - tags.push({ - value: 'frameworks', - short: 'Integrated Frameworks', - color: '#E78625', - }); - } - if (item.biofin === '1') { - tags.push({ - value: 'biofin', - short: 'Biodiversity finance', - color: '#E0529E', - }); + const allProgrammes = PROGRAMMES.find(p => p.value === 'all_programmes'); + + return ( + allProgrammes?.subprogrammes + ?.filter(program => { + if (program.subprogrammes) { + return program.subprogrammes.some(sub => item[sub.value] === '1'); + } + return item[program.value] === '1'; + }) + .map(program => ({ + value: program.value, + short: program.short, + color: program.color, + })) + .filter(program => selectedCheckboxes.includes(program.value)) || [] + ); + } + + // Handle cases for individual programmes + if (currentProgramme.subprogrammes) { + const subprogrammeTags = currentProgramme.subprogrammes + .filter(sub => item[sub.value] === '1') + .map(sub => sub); + + if (subprogrammeTags.length > 0) { + return subprogrammeTags; } + } - return tags.filter(tag => selectedCheckboxes.includes(tag.value)); + if (item[currentProgramme.value] === '1') { + return [currentProgramme]; } - return subProgrammes.filter( - program => - item[program.value] === '1' && - selectedCheckboxes.includes(program.value), - ); + return []; }; return ( @@ -149,9 +111,9 @@ function Cards(props: Props) { /> {filteredData.map((item, index) => { - const subProgrammesForCountry = getProgramTags(item); + const programTagsForCountry = getProgramTags(item); - const showCard = subProgrammesForCountry.length > 0; + const showCard = programTagsForCountry.length > 0; if (!showCard) return null; @@ -166,7 +128,7 @@ function Cards(props: Props) { - {subProgrammesForCountry.map(program => ( + {programTagsForCountry.map(program => ( {program.short} diff --git a/src/Components/Constants.tsx b/src/Components/Constants.tsx index 7c26335..2bb400b 100644 --- a/src/Components/Constants.tsx +++ b/src/Components/Constants.tsx @@ -1,50 +1,104 @@ import { Leaf, School, BriefcaseBusiness, Flag, Shell } from 'lucide-react'; -// constants.ts export interface Programme { - [x: number]: any; label: string; short: string; value: string; color: string; icon: any; + subprogrammes?: Programme[]; } -export const PROGRAMMES = [ +export const PROGRAMMES: Programme[] = [ { label: 'All Programmes', short: 'All Programmes', value: 'all_programmes', color: '#006EB5', icon: Leaf, - }, - { - label: 'Public finance for the SDGs', - short: 'Public finance', - value: 'public', - color: '#5DD4F0', - icon: School, - }, - { - label: 'Unlocking private capital and aligning for the SDGs', - short: 'Private finance', - value: 'private', - color: '#02A38A', - icon: BriefcaseBusiness, - }, - { - label: 'Integrated National Financing Frameworks', - short: 'Integrated Frameworks', - value: 'frameworks', - color: '#E78625', - icon: Flag, - }, - { - label: 'Biodiversity Finance', - short: 'Biodiversity finance', - value: 'biofin', - color: '#E0529E', - icon: Shell, + subprogrammes: [ + { + label: 'Public finance for the SDGs', + short: 'Public finance', + value: 'public', + color: '#5DD4F0', + icon: School, + subprogrammes: [ + { + label: 'Budget for the SDGs', + short: 'Budget for the SDGs', + value: 'public_budget', + color: '#5DD4F0', + icon: Leaf, + }, + { + label: 'Tax for the SDGs', + short: 'Tax for the SDGs', + value: 'public_tax', + color: '#5DD4F0', + icon: School, + }, + { + label: 'Debt for the SDGs', + short: 'Debt for the SDGs', + value: 'public_debt', + color: '#5DD4F0', + icon: BriefcaseBusiness, + }, + { + label: 'Insurance and Risk Finance', + short: 'Insurance and Risk Finance', + value: 'public_insurance', + color: '#5DD4F0', + icon: Flag, + }, + ], + }, + { + label: 'Unlocking private capital and aligning for the SDGs', + short: 'Private finance', + value: 'private', + color: '#02A38A', + icon: BriefcaseBusiness, + subprogrammes: [ + { + label: 'Originating pipelines', + short: 'Originating pipelines', + value: 'private_pipelines', + color: '#02A38A', + icon: Shell, + }, + { + label: 'Managing for Impact', + short: 'Managing for Impact', + value: 'private_impact', + color: '#02A38A', + icon: Leaf, + }, + { + label: 'Enabling environment', + short: 'Enabling environment', + value: 'private_environment', + color: '#02A38A', + icon: School, + }, + ], + }, + { + label: 'Integrated National Financing Frameworks', + short: 'Integrated Frameworks', + value: 'frameworks', + color: '#E78625', + icon: Flag, + }, + { + label: 'Biodiversity Finance', + short: 'Biodiversity finance', + value: 'biofin', + color: '#E0529E', + icon: Shell, + }, + ], }, ]; @@ -54,69 +108,3 @@ export const GROUPS = [ { label: 'LDC', value: 'ldc' }, { label: 'SIDS', value: 'sids' }, ]; - -export const SPECIFIED_PROGRAMMES = [ - { - label: 'Budget for the SDGs', - short: 'Budget for the SDGs', - value: 'public_budget', - color: '#5DD4F0', - icon: Leaf, - }, - { - label: 'Tax for the SDGs', - short: 'Tax for the SDGs', - value: 'public_tax', - color: '#5DD4F0', - icon: School, - }, - { - label: 'Debt for the SDGs', - short: 'Debt for the SDGs', - value: 'public_debt', - color: '#5DD4F0', - icon: BriefcaseBusiness, - }, - { - label: 'Insurance and Risk Finance', - short: 'Insurance and Risk Finance', - value: 'public_insurance', - color: '#5DD4F0', - icon: Flag, - }, - { - label: 'Originating pipelines', - short: 'Originating pipelines', - value: 'private_pipelines', - color: '#02A38A', - icon: Shell, - }, - { - label: 'Managing for Impact', - short: 'Managing for Impact', - value: 'private_impact', - color: '#02A38A', - icon: Leaf, - }, - { - label: 'Enabling environment', - short: 'Enabling environment', - value: 'private_environment', - color: '#02A38A', - icon: School, - }, - { - label: 'Integrated National Financing Frameworks', - short: 'Integrated Frameworks', - value: 'frameworks', - color: '#E78625', - icon: BriefcaseBusiness, - }, - { - label: 'Biofin', - short: 'Biofin', - value: 'biofin', - color: '#E0529E', - icon: Flag, - }, -]; diff --git a/src/Components/Graphs/Maps/ChoroplethMap/index.tsx b/src/Components/Graphs/Maps/ChoroplethMap/index.tsx index 952530f..5a21eac 100644 --- a/src/Components/Graphs/Maps/ChoroplethMap/index.tsx +++ b/src/Components/Graphs/Maps/ChoroplethMap/index.tsx @@ -43,8 +43,12 @@ export function ChoroplethMap(props: Props) { const { currentProgramme } = useProgramme(); const currentProgrammeColor = - PROGRAMMES.find(prog => prog.value === currentProgramme.value)?.color || - '#000000'; + PROGRAMMES.find(prog => + prog.subprogrammes?.some( + subprog => subprog.value === currentProgramme.value, + ), + )?.subprogrammes?.find(subprog => subprog.value === currentProgramme.value) + ?.color || '#006EB5'; const [svgWidth, setSvgWidth] = useState(0); const [svgHeight, setSvgHeight] = useState(0); diff --git a/src/Components/Header.tsx b/src/Components/Header.tsx index bb6a0c6..381e9e8 100644 --- a/src/Components/Header.tsx +++ b/src/Components/Header.tsx @@ -16,15 +16,16 @@ const StyledSegmented = styled(Segmented)<{ selectedColor: string }>` flex: 1; color: var(--gray-700); display: flex; - justify-content: flex-start; + justify-content: center; /* Center align text */ &:not(:last-child) { - margin-right: 4px; // Add gap between items except the last one + margin-right: 4px; /* Add gap between items except the last one */ } } .ant-segmented-item-label { white-space: normal; display: flex; + justify-content: center; /* Center align text */ padding: 0 !important; } @@ -37,20 +38,42 @@ const StyledSegmented = styled(Segmented)<{ selectedColor: string }>` `; interface HeaderProps { - onSegmentChange: (value: any) => void; // Callback function prop + onSegmentChange: (value: string | number) => void; // Callback function prop } function Header(props: HeaderProps): JSX.Element { const { onSegmentChange } = props; const { currentProgramme } = useProgramme(); + // Get the "All Programmes" option + const allProgrammesOption = PROGRAMMES.find( + programme => programme.value === 'all_programmes', + ); + + // Get all main subprogrammes under 'all_programmes' + const mainSubprogrammes = allProgrammesOption?.subprogrammes || []; + + // Prepare the options for the Segmented component + const options = [ + { + label: ( +

{allProgrammesOption?.short}

+ ), + value: allProgrammesOption?.value || 'all_programmes', + }, + ...mainSubprogrammes.map(programme => ({ + label:

{programme.short}

, + value: programme.value, + })), + ]; + return (

About Dashboard @@ -76,20 +99,9 @@ function Header(props: HeaderProps): JSX.Element {

({ - label: ( -

- {programme.short} -

- ), - value: programme.value, - }))} + options={options} onChange={onSegmentChange} + value={currentProgramme.value} />
); diff --git a/src/Components/Summary.tsx b/src/Components/Summary.tsx deleted file mode 100644 index 8368039..0000000 --- a/src/Components/Summary.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; -import { PROGRAMMES, SPECIFIED_PROGRAMMES } from './Constants'; -import { useProgramme } from './ProgrammeContext'; - -const SummaryItem = styled.div` - display: flex; - justify-content: space-between; - padding: 8px 0; - border-bottom: 1px solid var(--gray-300); - - &:last-child { - border-bottom: none; - } -`; - -interface SummaryProps { - totals: { [key: string]: number }; -} - -interface SummaryItemType { - label: string; - value: string; - short?: string; -} - -function Summary(props: SummaryProps) { - const { totals } = props; - const { currentProgramme } = useProgramme(); - - const renderSummaryItems = () => { - let summaryItems: SummaryItemType[] = []; - - if (currentProgramme.value === 'all_programmes') { - summaryItems = PROGRAMMES; - } else if (currentProgramme.value === 'public') { - summaryItems = [ - { - label: 'Public finance for the SDGs', - short: 'Public finance for the SDGs', - value: 'public', - }, - ...SPECIFIED_PROGRAMMES.filter(prog => - [ - 'public_budget', - 'public_tax', - 'public_debt', - 'public_insurance', - ].includes(prog.value), - ), - ]; - } else if (currentProgramme.value === 'private') { - summaryItems = [ - { - label: 'Unlocking private capital and aligning for the SDGs', - short: 'Unlocking private capital', - value: 'private', - }, - ...SPECIFIED_PROGRAMMES.filter(prog => - [ - 'private_pipelines', - 'private_impact', - 'private_environment', - ].includes(prog.value), - ), - ]; - } else { - summaryItems = [currentProgramme]; - } - - return ( -
- {summaryItems.length > 0 && ( -
-

{summaryItems[0].short}

-

- {totals[summaryItems[0].value] || 0} -

-
- )} - {summaryItems.slice(1).map(item => ( - -
{item.short}
-
- {totals[item.value] || 0} -
-
- ))} -
- ); - }; - - return
{renderSummaryItems()}
; -} - -export default Summary;