From 3b8b681df011484053d56d07d77917611ac1bea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Gonz=C3=A1lez?= Date: Tue, 12 Mar 2024 13:00:43 +0100 Subject: [PATCH] EUDR: API connection --- .../breakdown/breakdown-item/utils.ts | 2 +- .../deforestation-free-suppliers/index.tsx | 94 ++++++------- .../index.tsx | 93 ++++++------- .../suppliers-with-no-location-data/index.tsx | 93 ++++++------- .../analysis-eudr/category-list/index.tsx | 96 +++++++------- .../filters/years-range/index.tsx | 4 +- .../supplier-list-table/table/columns.tsx | 23 ++-- .../supplier-list-table/table/index.tsx | 33 +++-- .../supplier-list-table/table/mock-data.ts | 108 --------------- .../suppliers-stacked-bar/component.tsx | 124 ++++++++++-------- client/src/hooks/eudr/index.ts | 35 +++++ client/src/store/features/eudr/index.ts | 2 +- 12 files changed, 317 insertions(+), 390 deletions(-) delete mode 100644 client/src/containers/analysis-eudr/supplier-list-table/table/mock-data.ts diff --git a/client/src/containers/analysis-eudr/category-list/breakdown/breakdown-item/utils.ts b/client/src/containers/analysis-eudr/category-list/breakdown/breakdown-item/utils.ts index d8b863d73..fc6402ed4 100644 --- a/client/src/containers/analysis-eudr/category-list/breakdown/breakdown-item/utils.ts +++ b/client/src/containers/analysis-eudr/category-list/breakdown/breakdown-item/utils.ts @@ -17,7 +17,7 @@ const SVGS_DICTIONARY = { rubber: RubberSVG, wood: WoodSVG, coffee: CoffeeSVG, - 'palm-oil': PalmOilSVG, + 'Palm oil and its fractions': PalmOilSVG, cattle: CattleSVG, }; diff --git a/client/src/containers/analysis-eudr/category-list/breakdown/deforestation-free-suppliers/index.tsx b/client/src/containers/analysis-eudr/category-list/breakdown/deforestation-free-suppliers/index.tsx index eac14d37d..1b4d38cf1 100644 --- a/client/src/containers/analysis-eudr/category-list/breakdown/deforestation-free-suppliers/index.tsx +++ b/client/src/containers/analysis-eudr/category-list/breakdown/deforestation-free-suppliers/index.tsx @@ -3,66 +3,54 @@ import Flag from 'react-world-flags'; import { getCommodityIconByName } from '../breakdown-item/utils'; import Breakdown from '..'; +import { CATEGORIES } from '../..'; import { eudr } from '@/store/features/eudr'; import { useAppSelector } from '@/store/hooks'; -import { themeColors } from 'utils/colors'; +import { dateFormatter, useEUDRData } from '@/hooks/eudr'; import type BreakdownItem from '../breakdown-item'; -import type { CommodityName } from '../breakdown-item/utils'; - -type CommonData = { - name: string; - value: number; -}; - -type CommodityData = CommonData & { - name: CommodityName; -}; - -type CountryData = CommonData & { - iso3: string; -}; - -const SAMPLE_DATA: { commodities: CommodityData[]; countries: CountryData[] } = { - commodities: [ - { name: 'cattle', value: 80 }, - { name: 'cocoa', value: 22 }, - { name: 'coffee', value: 54 }, - { name: 'palm-oil', value: 50 }, - { name: 'wood', value: 11 }, - { name: 'soy', value: 5 }, - { name: 'rubber', value: 70 }, - ], - countries: [ - { name: 'Italy', value: 33, iso3: 'ITA' }, - { name: 'Spain', value: 56, iso3: 'ESP' }, - { name: 'Brazil', value: 8, iso3: 'BRA' }, - ], -}; - -export const CATEGORY_COLOR = themeColors.blue[400]; const DeforestationFreeSuppliersBreakdown = () => { - const { viewBy } = useAppSelector(eudr); - - const data: ComponentProps[] = useMemo(() => { - if (viewBy === 'commodities') { - return SAMPLE_DATA[viewBy].map((item) => ({ - ...item, - color: CATEGORY_COLOR, - icon: getCommodityIconByName(item.name, { fill: CATEGORY_COLOR }), - })); - } - - return SAMPLE_DATA[viewBy].map((item) => ({ - ...item, - color: CATEGORY_COLOR, - icon: , - })); - }, [viewBy]); - - return ; + const { + viewBy, + filters: { dates, suppliers, origins, materials }, + } = useAppSelector(eudr); + + const { data } = useEUDRData( + { + startAlertDate: dateFormatter(dates.from), + endAlertDate: dateFormatter(dates.to), + producerIds: suppliers?.map(({ value }) => value), + materialIds: materials?.map(({ value }) => value), + originIds: origins?.map(({ value }) => value), + }, + { + select: (data) => data?.breakDown, + }, + ); + + const parsedData: ComponentProps[] = useMemo(() => { + const dataByView = data?.[viewBy] || []; + + return Object.keys(dataByView) + .filter((key) => key === CATEGORIES[0].name) + .map((filteredKey) => + dataByView[filteredKey].detail + .map((item) => ({ + ...item, + color: CATEGORIES[0].color, + icon: getCommodityIconByName(item.name, { fill: CATEGORIES[0].color }), + ...(viewBy === 'origins' && { + icon: , + }), + })) + .flat(), + ) + .flat(); + }, [data, viewBy]); + + return ; }; export default DeforestationFreeSuppliersBreakdown; diff --git a/client/src/containers/analysis-eudr/category-list/breakdown/suppliers-with-deforestation-alerts/index.tsx b/client/src/containers/analysis-eudr/category-list/breakdown/suppliers-with-deforestation-alerts/index.tsx index c73da1539..62e82bae4 100644 --- a/client/src/containers/analysis-eudr/category-list/breakdown/suppliers-with-deforestation-alerts/index.tsx +++ b/client/src/containers/analysis-eudr/category-list/breakdown/suppliers-with-deforestation-alerts/index.tsx @@ -3,65 +3,54 @@ import Flag from 'react-world-flags'; import { getCommodityIconByName } from '../breakdown-item/utils'; import Breakdown from '..'; +import { CATEGORIES } from '../..'; import { eudr } from '@/store/features/eudr'; import { useAppSelector } from '@/store/hooks'; +import { dateFormatter, useEUDRData } from '@/hooks/eudr'; import type BreakdownItem from '../breakdown-item'; -import type { CommodityName } from '../breakdown-item/utils'; - -type CommonData = { - name: string; - value: number; -}; - -type CommodityData = CommonData & { - name: CommodityName; -}; - -type CountryData = CommonData & { - iso3: string; -}; - -const SAMPLE_DATA: { commodities: CommodityData[]; countries: CountryData[] } = { - commodities: [ - { name: 'cattle', value: 80 }, - { name: 'cocoa', value: 22 }, - { name: 'coffee', value: 54 }, - { name: 'palm-oil', value: 50 }, - { name: 'wood', value: 11 }, - { name: 'soy', value: 5 }, - { name: 'rubber', value: 70 }, - ], - countries: [ - { name: 'Italy', value: 33, iso3: 'ITA' }, - { name: 'Spain', value: 56, iso3: 'ESP' }, - { name: 'Brazil', value: 8, iso3: 'BRA' }, - ], -}; - -export const CATEGORY_COLOR = '#FFC038'; const SuppliersWithDeforestationAlertsBreakdown = () => { - const { viewBy } = useAppSelector(eudr); - - const data: ComponentProps[] = useMemo(() => { - if (viewBy === 'commodities') { - return SAMPLE_DATA[viewBy].map((item) => ({ - ...item, - color: CATEGORY_COLOR, - icon: getCommodityIconByName(item.name, { fill: CATEGORY_COLOR }), - })); - } - - return SAMPLE_DATA[viewBy].map((item) => ({ - ...item, - color: CATEGORY_COLOR, - icon: , - })); - }, [viewBy]); - - return ; + const { + viewBy, + filters: { dates, suppliers, origins, materials }, + } = useAppSelector(eudr); + + const { data } = useEUDRData( + { + startAlertDate: dateFormatter(dates.from), + endAlertDate: dateFormatter(dates.to), + producerIds: suppliers?.map(({ value }) => value), + materialIds: materials?.map(({ value }) => value), + originIds: origins?.map(({ value }) => value), + }, + { + select: (data) => data?.breakDown, + }, + ); + + const parsedData: ComponentProps[] = useMemo(() => { + const dataByView = data?.[viewBy] || []; + + return Object.keys(dataByView) + .filter((key) => key === CATEGORIES[1].name) + .map((filteredKey) => + dataByView[filteredKey].detail + .map((item) => ({ + ...item, + color: CATEGORIES[1].color, + icon: getCommodityIconByName(item.name, { fill: CATEGORIES[1].color }), + ...(viewBy === 'origins' && { + icon: , + }), + })) + .flat(), + ) + .flat(); + }, [data, viewBy]); + + return ; }; export default SuppliersWithDeforestationAlertsBreakdown; diff --git a/client/src/containers/analysis-eudr/category-list/breakdown/suppliers-with-no-location-data/index.tsx b/client/src/containers/analysis-eudr/category-list/breakdown/suppliers-with-no-location-data/index.tsx index e9b78fdee..023c1c66c 100644 --- a/client/src/containers/analysis-eudr/category-list/breakdown/suppliers-with-no-location-data/index.tsx +++ b/client/src/containers/analysis-eudr/category-list/breakdown/suppliers-with-no-location-data/index.tsx @@ -3,65 +3,54 @@ import Flag from 'react-world-flags'; import { getCommodityIconByName } from '../breakdown-item/utils'; import Breakdown from '..'; +import { CATEGORIES } from '../..'; import { eudr } from '@/store/features/eudr'; import { useAppSelector } from '@/store/hooks'; +import { dateFormatter, useEUDRData } from '@/hooks/eudr'; import type BreakdownItem from '../breakdown-item'; -import type { CommodityName } from '../breakdown-item/utils'; - -type CommonData = { - name: string; - value: number; -}; - -type CommodityData = CommonData & { - name: CommodityName; -}; - -type CountryData = CommonData & { - iso3: string; -}; - -const SAMPLE_DATA: { commodities: CommodityData[]; countries: CountryData[] } = { - commodities: [ - { name: 'cattle', value: 80 }, - { name: 'cocoa', value: 22 }, - { name: 'coffee', value: 54 }, - { name: 'palm-oil', value: 50 }, - { name: 'wood', value: 11 }, - { name: 'soy', value: 5 }, - { name: 'rubber', value: 70 }, - ], - countries: [ - { name: 'Italy', value: 33, iso3: 'ITA' }, - { name: 'Spain', value: 56, iso3: 'ESP' }, - { name: 'Brazil', value: 8, iso3: 'BRA' }, - ], -}; - -export const CATEGORY_COLOR = '#8561FF'; const SuppliersWithNoLocationDataBreakdown = () => { - const { viewBy } = useAppSelector(eudr); - - const data: ComponentProps[] = useMemo(() => { - if (viewBy === 'commodities') { - return SAMPLE_DATA[viewBy].map((item) => ({ - ...item, - color: CATEGORY_COLOR, - icon: getCommodityIconByName(item.name, { fill: CATEGORY_COLOR }), - })); - } - - return SAMPLE_DATA[viewBy].map((item) => ({ - ...item, - color: CATEGORY_COLOR, - icon: , - })); - }, [viewBy]); - - return ; + const { + viewBy, + filters: { dates, suppliers, origins, materials }, + } = useAppSelector(eudr); + + const { data } = useEUDRData( + { + startAlertDate: dateFormatter(dates.from), + endAlertDate: dateFormatter(dates.to), + producerIds: suppliers?.map(({ value }) => value), + materialIds: materials?.map(({ value }) => value), + originIds: origins?.map(({ value }) => value), + }, + { + select: (data) => data?.breakDown, + }, + ); + + const parsedData: ComponentProps[] = useMemo(() => { + const dataByView = data?.[viewBy] || []; + + return Object.keys(dataByView) + .filter((key) => key === CATEGORIES[2].name) + .map((filteredKey) => + dataByView[filteredKey].detail + .map((item) => ({ + ...item, + color: CATEGORIES[2].color, + icon: getCommodityIconByName(item.name, { fill: CATEGORIES[2].color }), + ...(viewBy === 'origins' && { + icon: , + }), + })) + .flat(), + ) + .flat(); + }, [data, viewBy]); + + return ; }; export default SuppliersWithNoLocationDataBreakdown; diff --git a/client/src/containers/analysis-eudr/category-list/index.tsx b/client/src/containers/analysis-eudr/category-list/index.tsx index a245616f0..df17a827c 100644 --- a/client/src/containers/analysis-eudr/category-list/index.tsx +++ b/client/src/containers/analysis-eudr/category-list/index.tsx @@ -1,71 +1,83 @@ -import { useState } from 'react'; +import { useMemo, useState } from 'react'; -import DeforestationFreeSuppliersBreakdown, { - CATEGORY_COLOR as DEFORESTATION_FREE_SUPPLIERS_COLOR, -} from './breakdown/deforestation-free-suppliers'; -import SuppliersWithDeforestationAlertsBreakdown, { - CATEGORY_COLOR as SUPPLIERS_WITH_DEFORESTATION_ALERTS_COLOR, -} from './breakdown/suppliers-with-deforestation-alerts'; -import SuppliersWithNoLocationDataBreakdown, { - CATEGORY_COLOR as SUPPLIERS_WITH_NO_LOCATION_DATA_COLOR, -} from './breakdown/suppliers-with-no-location-data'; +import DeforestationFreeSuppliersBreakdown from './breakdown/deforestation-free-suppliers'; +import SuppliersWithDeforestationAlertsBreakdown from './breakdown/suppliers-with-deforestation-alerts'; +import SuppliersWithNoLocationDataBreakdown from './breakdown/suppliers-with-no-location-data'; import { Button } from '@/components/button'; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; -import { formatPercentage } from '@/utils/number-format'; import { cn } from '@/lib/utils'; +import { useEUDRData, dateFormatter } from '@/hooks/eudr'; +import { useAppSelector } from '@/store/hooks'; +import { eudr } from '@/store/features/eudr'; +import { themeColors } from '@/utils/colors'; -const CATEGORIES = [ +export const CATEGORIES = [ { name: 'Deforestation-free suppliers', - slug: 'deforestation-free-suppliers', - color: DEFORESTATION_FREE_SUPPLIERS_COLOR, - // todo move this value field to the component - value: 0.3, + color: themeColors.blue[400], }, { name: 'Suppliers with deforestation alerts', - slug: 'suppliers-with-deforestation-alerts', - color: SUPPLIERS_WITH_DEFORESTATION_ALERTS_COLOR, - // todo move this value field to the component - value: 0.6, + color: '#FFC038', }, { name: 'Suppliers with no location data', - slug: 'suppliers-with-no-location-data', - color: SUPPLIERS_WITH_NO_LOCATION_DATA_COLOR, - // todo move this value field to the component - value: 0.1, + color: '#8561FF', }, ] as const; -type CategoryState = Record<(typeof CATEGORIES)[number]['slug'], boolean>; +type CategoryState = Record<(typeof CATEGORIES)[number]['name'], boolean>; export const CategoryList = (): JSX.Element => { const [categories, toggleCategory] = useState( CATEGORIES.reduce( (acc, category) => ({ ...acc, - [category.slug]: false, + [category.name]: false, }), {} as CategoryState, ), ); - const categoriesWithValues = CATEGORIES.map((category) => ({ - ...category, - // todo: calculate value field here - })); + + const { + viewBy, + filters: { dates, suppliers, origins, materials }, + } = useAppSelector(eudr); + + const { data } = useEUDRData( + { + startAlertDate: dateFormatter(dates.from), + endAlertDate: dateFormatter(dates.to), + producerIds: suppliers?.map(({ value }) => value), + materialIds: materials?.map(({ value }) => value), + originIds: origins?.map(({ value }) => value), + }, + { + select: (data) => data?.breakDown, + }, + ); + + const parsedData = useMemo(() => { + const dataByView = data?.[viewBy] || []; + + return Object.keys(dataByView).map((key) => ({ + name: key, + ...dataByView[key], + color: CATEGORIES.find((category) => category.name === key)?.color || '#000', + })); + }, [data, viewBy]); return ( <> - {categoriesWithValues.map((category) => ( + {parsedData.map((category) => ( { toggleCategory((prev) => ({ ...prev, - [category.slug]: !prev[category.slug], + [category.name]: !prev[category.name], })); }} > @@ -84,13 +96,13 @@ export const CategoryList = (): JSX.Element => {
- {formatPercentage(category.value)} of suppliers + {`${category.totalPercentage}%`} of suppliers
@@ -104,24 +116,18 @@ export const CategoryList = (): JSX.Element => { className={cn( 'w-[98px] rounded-md border-none text-sm text-gray-500 shadow-none transition-colors hover:shadow-none', { - 'bg-navy-400 text-white hover:bg-navy-600': categories[category.slug], + 'bg-navy-400 text-white hover:bg-navy-600': categories[category.name], }, )} > - {categories[category.slug] ? 'Close detail' : 'View detail'} + {categories[category.name] ? 'Close detail' : 'View detail'}
- {category.slug === 'deforestation-free-suppliers' && ( - - )} - {category.slug === 'suppliers-with-deforestation-alerts' && ( - - )} - {category.slug === 'suppliers-with-no-location-data' && ( - - )} + {category.name === CATEGORIES[0].name && } + {category.name === CATEGORIES[1].name && } + {category.name === CATEGORIES[2].name && } ))} diff --git a/client/src/containers/analysis-eudr/filters/years-range/index.tsx b/client/src/containers/analysis-eudr/filters/years-range/index.tsx index f61f24266..cf9102ee6 100644 --- a/client/src/containers/analysis-eudr/filters/years-range/index.tsx +++ b/client/src/containers/analysis-eudr/filters/years-range/index.tsx @@ -1,6 +1,5 @@ import React, { useCallback } from 'react'; import { UTCDate } from '@date-fns/utc'; -import { format } from 'date-fns'; import { ChevronDown } from 'lucide-react'; import { useAppDispatch, useAppSelector } from 'store/hooks'; @@ -8,14 +7,13 @@ import { eudr, setFilters } from 'store/features/eudr'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { Button } from '@/components/ui/button'; import { Calendar } from '@/components/ui/calendar'; +import { dateFormatter } from '@/hooks/eudr'; import type { DateRange } from 'react-day-picker'; // ! the date range is hardcoded for now export const DATES_RANGE = [new UTCDate('2020-12-31'), new UTCDate()]; -const dateFormatter = (date: Date) => format(date, 'dd/MM/yyyy'); - const DatesRange = (): JSX.Element => { const dispatch = useAppDispatch(); const { diff --git a/client/src/containers/analysis-eudr/supplier-list-table/table/columns.tsx b/client/src/containers/analysis-eudr/supplier-list-table/table/columns.tsx index b338499dc..d863384ba 100644 --- a/client/src/containers/analysis-eudr/supplier-list-table/table/columns.tsx +++ b/client/src/containers/analysis-eudr/supplier-list-table/table/columns.tsx @@ -1,10 +1,9 @@ -'use client'; - import Link from 'next/link'; import { DataTableColumnHeader } from './column-header'; import { Badge } from '@/components/ui/badge'; +import { BIG_NUMBER_FORMAT } from 'utils/number-format'; import type { Supplier } from '.'; import type { ColumnDef } from '@tanstack/react-table'; @@ -17,7 +16,7 @@ export const columns: ColumnDef[] = [ return (
{row.getValue('supplierName')} @@ -34,11 +33,15 @@ export const columns: ColumnDef[] = [ enableHiding: false, }, { - accessorKey: 'baseLineVolume', + accessorKey: 'baselineVolume', header: ({ column }) => , cell: ({ row }) => { // todo: format number - return {row.getValue('baseLineVolume')}; + return ( +
+ {BIG_NUMBER_FORMAT(row.getValue('baselineVolume'))} +
+ ); }, }, { @@ -58,11 +61,11 @@ export const columns: ColumnDef[] = [ }, }, { - accessorKey: 'ttp', - header: ({ column }) => , + accessorKey: 'tpl', + header: ({ column }) => , cell: ({ row }) => { - const ttp = row.getValue('ttp'); - return {`${Number.isNaN(ttp) ? '-' : `${ttp}%`}`}; + const tpl = row.getValue('tpl'); + return {`${Number.isNaN(tpl) ? '-' : `${tpl}%`}`}; }, }, { @@ -86,7 +89,7 @@ export const columns: ColumnDef[] = [ }, { accessorKey: 'origins', - header: ({ column }) => , + header: ({ column }) => , cell: ({ row }) => { return (
diff --git a/client/src/containers/analysis-eudr/supplier-list-table/table/index.tsx b/client/src/containers/analysis-eudr/supplier-list-table/table/index.tsx index 575060a0a..b3b7c48e7 100644 --- a/client/src/containers/analysis-eudr/supplier-list-table/table/index.tsx +++ b/client/src/containers/analysis-eudr/supplier-list-table/table/index.tsx @@ -11,7 +11,6 @@ import { import { useState } from 'react'; import columns from './columns'; -import { MOCK_DATA } from './mock-data'; import { DataTablePagination, PAGINATION_SIZES } from './pagination'; import { @@ -22,7 +21,9 @@ import { TableBody, TableCell, } from '@/components/ui/table'; -// import { useEUDRSuppliers } from '@/hooks/eudr'; +import { useEUDRData, dateFormatter } from '@/hooks/eudr'; +import { useAppSelector } from '@/store/hooks'; +import { eudr } from '@/store/features/eudr'; import type { // ColumnFiltersState, @@ -31,13 +32,13 @@ import type { } from '@tanstack/react-table'; export interface Supplier { - id: number; + supplierId: number; supplierName: string; companyId: string; - baseLineVolume: number; + baselineVolume: number; dfs: number; sda: number; - ttp: number; + tpl: number; materials: { name: string; id: string; @@ -53,12 +54,22 @@ const SuppliersListTable = (): JSX.Element => { // const [columnVisibility, setColumnVisibility] = useState({}); // const [columnFilters, setColumnFilters] = useState([]); const [sorting, setSorting] = useState([]); + const { + filters: { dates, suppliers, origins, materials }, + } = useAppSelector(eudr); - const data = MOCK_DATA; - // const { data } = useEUDRSuppliers(undefined, { - // enabled: false, - // placeholderData: MOCK_DATA, - // }); + const { data } = useEUDRData( + { + startAlertDate: dateFormatter(dates.from), + endAlertDate: dateFormatter(dates.to), + producerIds: suppliers?.map(({ value }) => value), + materialIds: materials?.map(({ value }) => value), + originIds: origins?.map(({ value }) => value), + }, + { + select: (data) => data?.table, + }, + ); const table = useReactTable({ data: data, @@ -87,6 +98,8 @@ const SuppliersListTable = (): JSX.Element => { // getFacetedUniqueValues: getFacetedUniqueValues(), }); + if (!data?.length) return null; + return (
diff --git a/client/src/containers/analysis-eudr/supplier-list-table/table/mock-data.ts b/client/src/containers/analysis-eudr/supplier-list-table/table/mock-data.ts deleted file mode 100644 index 6d2868458..000000000 --- a/client/src/containers/analysis-eudr/supplier-list-table/table/mock-data.ts +++ /dev/null @@ -1,108 +0,0 @@ -import type { Supplier } from '.'; - -export const MOCK_DATA: Supplier[] = [ - { - id: 2, - supplierName: 'Very long name of supplier Very long name of supplier', - companyId: '123', - baseLineVolume: 1000, - dfs: 100, - sda: 39.7, - ttp: 40.1, - materials: [ - { name: 'Material 1', id: '1' }, - { name: 'Material 2', id: '2' }, - ], - origins: [ - { name: 'Origin 1', id: '1' }, - { name: 'Origin 2', id: '2' }, - ], - }, - { - id: 4, - supplierName: 'Supplier 2', - companyId: '124', - baseLineVolume: 2000, - dfs: 200, - sda: 39.7, - ttp: 40.1, - materials: [ - { name: 'Material 3', id: '3' }, - { name: 'Material 4', id: '4' }, - { name: 'Material 4', id: '5' }, - { name: 'Material 4', id: '6' }, - ], - origins: [ - { name: 'Origin 3', id: '3' }, - { name: 'Origin 4', id: '4' }, - ], - }, - { - id: 8, - supplierName: 'Supplier 3', - companyId: '125', - baseLineVolume: 3000, - dfs: 300, - sda: 39.7, - ttp: 40.1, - materials: [ - { name: 'Material 5', id: '5' }, - { name: 'Material 6', id: '6' }, - ], - origins: [ - { name: 'Origin 5', id: '5' }, - { name: 'Origin 6', id: '6' }, - ], - }, - { - id: 67, - supplierName: 'Supplier 3', - companyId: '125', - baseLineVolume: 3000, - dfs: 300, - sda: 39.7, - ttp: 40.1, - materials: [ - { name: 'Material 5', id: '5' }, - { name: 'Material 6', id: '6' }, - ], - origins: [ - { name: 'Origin 5', id: '5' }, - { name: 'Origin 6', id: '6' }, - ], - }, - { - id: 33, - supplierName: 'Supplier 3', - companyId: '125', - baseLineVolume: 3000, - dfs: 300, - sda: 39.7, - ttp: 40.1, - materials: [ - { name: 'Material 5', id: '5' }, - { name: 'Material 6', id: '6' }, - ], - origins: [ - { name: 'Origin 5', id: '5' }, - { name: 'Origin 6', id: '6' }, - ], - }, - { - id: 9, - supplierName: 'Supplier 3', - companyId: '125', - baseLineVolume: 3000, - dfs: 300, - sda: 39.7, - ttp: 40.1, - materials: [ - { name: 'Material 5', id: '5' }, - { name: 'Material 6', id: '6' }, - ], - origins: [ - { name: 'Origin 5', id: '5' }, - { name: 'Origin 6', id: '6' }, - ], - }, -]; diff --git a/client/src/containers/analysis-eudr/suppliers-stacked-bar/component.tsx b/client/src/containers/analysis-eudr/suppliers-stacked-bar/component.tsx index a647e2367..daeaab75d 100644 --- a/client/src/containers/analysis-eudr/suppliers-stacked-bar/component.tsx +++ b/client/src/containers/analysis-eudr/suppliers-stacked-bar/component.tsx @@ -1,4 +1,4 @@ -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { BarChart, Bar, @@ -9,71 +9,31 @@ import { ResponsiveContainer, Label, } from 'recharts'; +import { groupBy } from 'lodash-es'; -import CategoryList from '@/containers/analysis-eudr/category-list'; +import CategoryList, { CATEGORIES } from '@/containers/analysis-eudr/category-list'; import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { Label as RadioLabel } from '@/components/ui/label'; import { useAppDispatch, useAppSelector } from '@/store/hooks'; import { eudr, setViewBy } from '@/store/features/eudr'; +import { useEUDRData, dateFormatter } from '@/hooks/eudr'; export const VIEW_BY_OPTIONS = [ { label: 'Commodities', - value: 'commodities', + value: 'materials', }, { label: 'Countries', - value: 'countries', + value: 'origins', }, ] as const; -const data = [ - { - name: 'Cattle', - uv: 40, - pv: 30, - amt: 30, - }, - { - name: 'Cocoa', - uv: 30, - pv: 13, - amt: 57, - }, - { - name: 'Coffee', - uv: 20, - pv: 70, - amt: 10, - }, - { - name: 'Oil palm', - uv: 27, - pv: 39, - amt: 34, - }, - { - name: 'Wood', - uv: 28, - pv: 48, - amt: 24, - }, - { - name: 'Soya', - uv: 23, - pv: 38, - amt: 39, - }, - { - name: 'Rubber', - uv: 34, - pv: 43, - amt: 23, - }, -]; - const SuppliersStackedBar = () => { - const { viewBy } = useAppSelector(eudr); + const { + viewBy, + filters: { dates, suppliers, origins, materials }, + } = useAppSelector(eudr); const dispatch = useAppDispatch(); const handleViewBy = useCallback( @@ -83,11 +43,50 @@ const SuppliersStackedBar = () => { [dispatch], ); + const { data } = useEUDRData( + { + startAlertDate: dateFormatter(dates.from), + endAlertDate: dateFormatter(dates.to), + producerIds: suppliers?.map(({ value }) => value), + materialIds: materials?.map(({ value }) => value), + originIds: origins?.map(({ value }) => value), + }, + { + select: (data) => data?.breakDown, + }, + ); + + const parsedData = useMemo(() => { + const dataByView = data?.[viewBy] || []; + + const dataRootLevel = Object.keys(dataByView) + .map((key) => ({ + category: key, + ...dataByView[key], + })) + .map(({ detail, category }) => detail.map((x) => ({ ...x, category })).flat()) + .flat(); + + return Object.keys(groupBy(dataRootLevel, 'name')).map((material) => ({ + name: material, + free: dataRootLevel.find( + ({ name, category }) => name === material && category === 'Deforestation-free suppliers', + )?.value, + alerts: dataRootLevel.find( + ({ name, category }) => + name === material && category === 'Suppliers with deforestation alerts', + )?.value, + noData: dataRootLevel.find( + ({ name, category }) => name === material && category === 'Suppliers with no location data', + )?.value, + })); + }, [data, viewBy]); + return (
- Total numbers of suppliers: 46.53P + Total numbers of suppliers: {parsedData?.length || '-'}

Suppliers by category

@@ -113,7 +112,7 @@ const SuppliersStackedBar = () => { { width={200} /> - - - + + +
diff --git a/client/src/hooks/eudr/index.ts b/client/src/hooks/eudr/index.ts index aa86ec2ae..6d023c807 100644 --- a/client/src/hooks/eudr/index.ts +++ b/client/src/hooks/eudr/index.ts @@ -1,11 +1,15 @@ import { useQuery } from '@tanstack/react-query'; +import { format } from 'date-fns'; import { apiService } from 'services/api'; +import type { Supplier as SupplierRow } from '@/containers/analysis-eudr/supplier-list-table/table'; import type { AdminRegionsTreesParams } from '@/hooks/admin-regions'; import type { MaterialTreeItem, OriginRegion, Supplier } from '@/types'; import type { UseQueryOptions } from '@tanstack/react-query'; +export const dateFormatter = (date: Date) => format(date, 'yyyy-MM-dd'); + export const useEUDRSuppliers = ( params?: { producersIds: string[]; originsId: string[]; materialsId: string[] }, options: UseQueryOptions = {}, @@ -140,3 +144,34 @@ export const useEUDRAlertDates = ( }, ); }; + +interface EUDRData { + table: SupplierRow[]; + breakDown: []; +} + +export const useEUDRData = ( + params?: { + startAlertDate: string; + endAlertDate: string; + producerIds?: string[]; + materialIds?: string[]; + originIds?: string[]; + }, + options: UseQueryOptions = {}, +) => { + return useQuery( + ['eudr-table', params], + () => + apiService + .request({ + method: 'GET', + url: '/eudr/dashboard', + params, + }) + .then(({ data }) => data), + { + ...options, + }, + ); +}; diff --git a/client/src/store/features/eudr/index.ts b/client/src/store/features/eudr/index.ts index d90397b8e..83003f3a4 100644 --- a/client/src/store/features/eudr/index.ts +++ b/client/src/store/features/eudr/index.ts @@ -22,7 +22,7 @@ export type EUDRState = { }; export const initialState: EUDRState = { - viewBy: 'commodities', + viewBy: 'materials', filters: { materials: [], origins: [],