Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EUDR category breakdown #1122

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions client/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/styles/globals.css",
"baseColor": "slate",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
}
}
10 changes: 9 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
"@json2csv/plainjs": "^6.1.3",
"@loaders.gl/core": "3.3.1",
"@luma.gl/constants": "8.5.18",
"@radix-ui/react-collapsible": "1.0.3",
"@radix-ui/react-label": "2.0.2",
"@radix-ui/react-radio-group": "1.1.3",
"@reduxjs/toolkit": "1.8.2",
"@tailwindcss/forms": "0.4.0",
"@tailwindcss/typography": "0.5.0",
Expand All @@ -43,7 +46,9 @@
"autoprefixer": "10.2.5",
"axios": "1.3.4",
"chroma-js": "2.1.2",
"class-variance-authority": "0.7.0",
"classnames": "2.3.1",
"clsx": "^2.1.0",
"d3-array": "3.0.2",
"d3-format": "3.0.1",
"d3-scale": "4.0.2",
Expand All @@ -52,6 +57,7 @@
"jsona": "1.9.2",
"lodash-es": "4.17.21",
"lottie-react": "2.4.0",
"lucide-react": "0.344.0",
"maplibre-gl": "3.6.2",
"next": "13.5.5",
"next-auth": "4.19.2",
Expand All @@ -70,7 +76,9 @@
"recharts": "2.9.0",
"rooks": "7.14.1",
"sharp": "0.32.6",
"tailwindcss": "3.3.1",
"tailwind-merge": "2.2.1",
"tailwindcss": "3.4.1",
"tailwindcss-animate": "1.0.7",
"uuid": "8.3.2",
"yup": "0.32.11"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ const AutoCompleteSelect = <T,>({
{({ open }) => (
<>
{!!label && (
<Combobox.Label className="text-gray-700 block text-sm font-medium">
<Combobox.Label className="block text-sm font-medium text-gray-700">
{label}
</Combobox.Label>
)}
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/forms/select/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ const Select = <T,>({
{({ open }) => (
<>
{!!label && (
<Listbox.Label className="text-gray-700 block text-sm font-medium">
<Listbox.Label className="block text-sm font-medium text-gray-700">
{label}
</Listbox.Label>
)}
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/table/cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const CellWrapper = <T, C>({ children, context }: React.PropsWithChildren<CellPr
onClick={isExpandible ? toggleExpand : undefined}
className={classNames(
getAlignmentClasses(align),
'min-h-20 relative flex w-full items-center justify-start',
'relative flex min-h-20 w-full items-center justify-start',
{
'cursor-pointer': isExpandible,
'ml-7 pr-7': canExpand && !isExpandible && isFirstColumn,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const Table: React.FC<ButtonProps> = ({
'flex h-10 min-w-[2.5rem] items-center justify-center text-sm',
className,
{
'border-green-700 border-b': active,
'border-b border-green-700': active,
'cursor-pointer': !disabled,
'opacity-30': disabled,
},
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/tabs/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const Tabs: React.FC<TabsProps> = ({ activeTab, tabs, bottomBorder = true }: Tab
href={tab.href}
className={classNames('-mb-px py-3', {
'ml-10': index !== 0,
'text-green-700 border-green-700 border-b-2': activeTab && tab === activeTab,
'border-b-2 border-green-700 text-green-700': activeTab && tab === activeTab,
})}
>
{tab.name}
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/tree-select/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ const InnerTreeSelect = <IsMulti extends boolean>(
{theme === 'inline-primary' ? (
<div
className={classNames(
'border-t-primary mx-auto mt-0.5 h-0 w-0 border-x-4 border-t-4 border-x-transparent',
'mx-auto mt-0.5 h-0 w-0 border-x-4 border-t-4 border-x-transparent border-t-primary',
{ 'border-t-red-400': error },
)}
/>
Expand Down
9 changes: 9 additions & 0 deletions client/src/components/ui/collapsible.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';

const Collapsible = CollapsiblePrimitive.Root;

const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;

const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;

export { Collapsible, CollapsibleTrigger, CollapsibleContent };
19 changes: 19 additions & 0 deletions client/src/components/ui/label.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as React from 'react';
import * as LabelPrimitive from '@radix-ui/react-label';
import { cva, type VariantProps } from 'class-variance-authority';

import { cn } from '@/lib/utils';

const labelVariants = cva(
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
);

const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => (
<LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />
));
Label.displayName = LabelPrimitive.Root.displayName;

export { Label };
36 changes: 36 additions & 0 deletions client/src/components/ui/radio-group.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as React from 'react';
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
import { Circle } from 'lucide-react';

import { cn } from '@/lib/utils';

const RadioGroup = React.forwardRef<
React.ElementRef<typeof RadioGroupPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
>(({ className, ...props }, ref) => {
return <RadioGroupPrimitive.Root className={cn('grid gap-2', className)} {...props} ref={ref} />;
});
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;

const RadioGroupItem = React.forwardRef<
React.ElementRef<typeof RadioGroupPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
>(({ className, ...props }, ref) => {
return (
<RadioGroupPrimitive.Item
ref={ref}
className={cn(
'aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
className,
)}
{...props}
>
<RadioGroupPrimitive.Indicator className="flex items-center justify-center">
<Circle className="h-2.5 w-2.5 fill-current text-current" />
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
);
});
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;

export { RadioGroup, RadioGroupItem };
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { formatPercentage } from '@/utils/number-format';

const BreakdownItem = ({
name,
color,
icon,
value,
}: {
name: string;
color: string;
icon: string;
value: number;
}): JSX.Element => {
return (
<div className="flex items-center justify-between">
<div className="flex items-center">
<div className="mr-2 h-2 w-2 rounded-full bg-[#4AB7F3]" />
<span>{name}</span>
</div>
<div className="shrink-0 grow-0">
<div className="text-center">
{formatPercentage(value)} <span className="text-xs">of suppliers</span>
</div>
<div className="h-[2px] w-[340px] bg-gray-200">
<div className={`h-[2px] ${color}`} style={{ width: formatPercentage(value) }} />
</div>
</div>
</div>
);
};

export default BreakdownItem;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const SAMPLE_DATA = {
byMaterial: [
{ name: 'Supplier 1', value: 100 },
{ name: 'Supplier 1', value: 100 },
],
byOrigin: [
{ name: 'Supplier 1', value: 100, iso3: 'ITA' },
{ name: 'Supplier 1', value: 100, iso3: 'ITA' },
],
};

const DeforestationFreeSuppliersBreakdown = () => {
return <div>DeforestationFreeSuppliersBreakdown</div>;
};

export default DeforestationFreeSuppliersBreakdown;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const SuppliersWithDeforestationAlertsBreakdown = () => {
return <div>SuppliersWithDeforestationAlertsBreakdown</div>;
};

export default SuppliersWithDeforestationAlertsBreakdown;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const SuppliersWithNoLocationDataBreakdown = () => {
return <div>SuppliersWithNoLocationData</div>;
};

export default SuppliersWithNoLocationDataBreakdown;
101 changes: 101 additions & 0 deletions client/src/containers/analysis-eudr/category-list/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { useState } from 'react';

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';

const CATEGORIES = [
{
name: 'Deforestation-free suppliers',
slug: 'deforestation-free-suppliers',
color: 'bg-[#4AB7F3]',
// todo move this value field to the component
value: 0.3,
},
{
name: 'Suppliers with deforestation alerts',
slug: 'suppliers-with-deforestation-alerts',
color: 'bg-[#FFC038]',
// todo move this value field to the component
value: 0.6,
},
{
name: 'Suppliers with no location data',
slug: 'suppliers-with-no-location-data',
color: 'bg-[#8460FF]',
// todo move this value field to the component
value: 0.1,
},
] as const;

type CategoryState = Record<(typeof CATEGORIES)[number]['slug'], boolean>;

export const CategoryList = (): JSX.Element => {
const [categories, toggleCategory] = useState<CategoryState>(
CATEGORIES.reduce(
(acc, category) => ({
...acc,
[category.slug]: false,
}),
{} as CategoryState,
),
);
const categoriesWithValues = CATEGORIES.map((category) => ({
...category,
// todo: calculate value field here
}));

return (
<>
{categoriesWithValues.map((category) => (
<Collapsible
key={category.slug}
className="rounded-xl bg-gray-50 p-5"
onOpenChange={() => {
toggleCategory((prev) => ({
...prev,
[category.slug]: !prev[category.slug],
}));
}}
>
<div className="flex w-full items-center space-x-6">
<div className="flex-1 text-left">{category.name}</div>
<div className="shrink-0 grow-0">
<div className="text-center">
{formatPercentage(category.value)} <span className="text-xs">of suppliers</span>
</div>
<div className="h-[2px] w-[340px] bg-gray-200">
<div
className={`h-[2px] ${category.color}`}
style={{ width: formatPercentage(category.value) }}
/>
</div>
</div>
<CollapsibleTrigger asChild>
<Button type="button" size="xs" variant="white">
{categories[category.slug] ? 'Close details' : 'View details'}
</Button>
</CollapsibleTrigger>
</div>
<CollapsibleContent>
{category.slug === 'deforestation-free-suppliers' && (
<DeforestationFreeSuppliersBreakdown />
)}
{category.slug === 'suppliers-with-deforestation-alerts' && (
<SuppliersWithDeforestationAlertsBreakdown />
)}
{category.slug === 'suppliers-with-no-location-data' && (
<SuppliersWithNoLocationDataBreakdown />
)}
</CollapsibleContent>
</Collapsible>
))}
</>
);
};

export default CategoryList;
Loading
Loading