Skip to content

Commit

Permalink
show more badges
Browse files Browse the repository at this point in the history
  • Loading branch information
mluena committed Feb 20, 2024
1 parent aa4db80 commit 912a76b
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 74 deletions.
14 changes: 8 additions & 6 deletions client/src/app/projects/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ export const metadata: Metadata = {
title: 'AFoCO | Projects',
description: '',
};

import Filters from '@/containers/filters';
import Panel from '@/containers/panel';
import ProjectsList from '@/containers/projects/list';

export default function Projects() {
return (
<div className="space-y-5 p-5">
<h2 className="text-3xl font-normal">Projects</h2>
<Filters />
<ProjectsList />
</div>
<Panel>
<div className="space-y-5 p-5">
<h2 className="text-3xl font-normal">Projects</h2>
<Filters />
<ProjectsList />
</div>
</Panel>
);
}
6 changes: 3 additions & 3 deletions client/src/components/ui/combobox.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import * as React from 'react';
import { useState } from 'react';

import { Check } from 'lucide-react';
import { RiSearchLine } from 'react-icons/ri';
Expand Down Expand Up @@ -28,8 +28,8 @@ export function Combobox({
options: Record<string, string>[];
onClick?: (e: string) => void;
}) {
const [open, setOpen] = React.useState(false);
const [value, setValue] = React.useState('');
const [open, setOpen] = useState(false);
const [value, setValue] = useState('');
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/ui/command.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import { forwardRef, ElementRef, ComponentPropsWithoutRef } from 'react';
import { forwardRef, ElementRef, ComponentPropsWithoutRef, HTMLAttributes } from 'react';

import { type DialogProps } from '@radix-ui/react-dialog';
import { Command as CommandPrimitive } from 'cmdk';
Expand Down
6 changes: 1 addition & 5 deletions client/src/components/ui/popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@ import { cn } from '@/lib/classnames';

const Popover = PopoverPrimitive.Root;

const PopoverTrigger = React.forwardRef<
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Trigger>
>(({ ...props }) => <PopoverPrimitive.Trigger className=" flex-1" {...props} />);

PopoverTrigger.displayName = PopoverPrimitive.Trigger.displayName;
const PopoverTrigger = PopoverPrimitive.Trigger;

const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
Expand Down
73 changes: 73 additions & 0 deletions client/src/containers/filters/badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
'use client';

import { useCallback } from 'react';

import { useAtom } from 'jotai';
import { X } from 'lucide-react';

import { filtersAtom } from '@/store/projects';

import { useSyncFilters } from '@/hooks/datasets/sync-query';

import type { FiltersType, FilterValues } from '@/containers/filters/types';

import { CATEGORIES_FILTERS_DICTIONARY } from './constants';

export default function FiltersBadge({
category,
filterValue,
}: {
category: FiltersType;
filterValue: FilterValues;
}) {
const [filtersSettings, setFilters] = useAtom(filtersAtom);
const [, setFiltersToURL] = useSyncFilters();

const handleResetFilter = useCallback(
(category: FiltersType, filterValue: FilterValues) => {
const filterSettingsCategory: FilterValues | undefined = filtersSettings[category];

// Check if filterSettingsCategory is not undefined and is an array
if (Array.isArray(filterSettingsCategory)) {
const filtersUpdate = {
...filtersSettings,
[category]: filterSettingsCategory.filter((f) => f !== filterValue),
};
setFilters(filtersUpdate);
setFiltersToURL(filtersUpdate);
} else if (
typeof filterSettingsCategory === 'string' &&
filterSettingsCategory === filterValue
) {
// If filterSettingsCategory is a string and matches filterValue, remove it by setting it to an empty array or handling as needed
const { [category]: _, ...restFiltersSettings } = filtersSettings;
const filtersUpdate = {
...restFiltersSettings,
// Optionally, handle the removal of a string filter differently here
};
setFilters(filtersUpdate);
setFiltersToURL(filtersUpdate);
}
},
[setFilters, setFiltersToURL, filtersSettings]
);

return (
<li
key={`${category}-${filterValue}`}
className="rounded-2xl border-yellow-500 bg-yellow-50 p-1 text-yellow-800"
>
<button
type="button"
className="flex items-center space-x-2 px-1"
onClick={() => handleResetFilter(category as FiltersType, filterValue as FilterValues)}
>
<div className="space-x-1">
<span>{CATEGORIES_FILTERS_DICTIONARY[category]}</span>
<span className="font-bold">{filterValue}</span>
</div>
<X className="h-2 w-2 fill-current stroke-yellow-900 text-yellow-900" />
</button>
</li>
);
}
8 changes: 8 additions & 0 deletions client/src/containers/filters/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ export const INTERVENTION_TYPES = [
{ id: 'restoration-and-revegetation', label: 'Restoration & Revegetation' },
];

export const CATEGORIES_FILTERS_DICTIONARY: { [key: string]: string } = {
intervention: 'Intervention type',
country: 'Country',
area_restored: 'Restored area',
area_protected: 'Protected area',
area_plantation: 'Plantation area',
};

export const AREAS = [
{
id: '<200',
Expand Down
86 changes: 29 additions & 57 deletions client/src/containers/filters/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
import { useCallback } from 'react';

import { useAtom } from 'jotai';
import { X } from 'lucide-react';
import { LuFilter } from 'react-icons/lu';

import { filtersAtom } from '@/store/projects';

import { useSyncFilters } from '@/hooks/datasets/sync-query';

import FiltersContent from '@/containers/filters/content';
import type { FiltersType, FilterValues } from '@/containers/filters/types';
import type { FiltersType } from '@/containers/filters/types';

import { Button } from '@/components/ui/button';
import { Combobox } from '@/components/ui/combobox';
Expand All @@ -24,6 +23,7 @@ import {
DialogTrigger,
} from '@/components/ui/dialog';

import FiltersBadge from './badge';
import { PROJECTS } from './constants';

export default function Filters() {
Expand All @@ -34,35 +34,6 @@ export default function Filters() {
setFiltersToURL({});
}, [setFilters, setFiltersToURL]);

const handleResetFilter = useCallback(
(category: FiltersType, filterValue: FilterValues) => {
const filterSettingsCategory: FilterValues | undefined = filtersSettings[category];

// Check if filterSettingsCategory is not undefined and is an array
if (Array.isArray(filterSettingsCategory)) {
const filtersUpdate = {
...filtersSettings,
[category]: filterSettingsCategory.filter((f) => f !== filterValue),
};
setFilters(filtersUpdate);
setFiltersToURL(filtersUpdate);
} else if (
typeof filterSettingsCategory === 'string' &&
filterSettingsCategory === filterValue
) {
// If filterSettingsCategory is a string and matches filterValue, remove it by setting it to an empty array or handling as needed
const { [category]: _, ...restFiltersSettings } = filtersSettings;
const filtersUpdate = {
...restFiltersSettings,
// Optionally, handle the removal of a string filter differently here
};
setFilters(filtersUpdate);
setFiltersToURL(filtersUpdate);
}
},
[setFilters, setFiltersToURL, filtersSettings]
);

return (
<div className="space-y-2">
<div className="flex space-x-2">
Expand Down Expand Up @@ -95,32 +66,33 @@ export default function Filters() {
<div className="text-xs text-gray-500">
<span className="-tracking-wide">Filtered by</span>
<ul>
{Object.entries(filtersSettings).map(([category, filterValues]) => (
<li key={category as FiltersType}>
<span className="font-bold">{category}</span>
<ul className="flex flex-wrap gap-1">
{(Array.isArray(filterValues) ? filterValues : [filterValues]).map(
(filterValue) => (
<li
key={`${category}-${filterValue}`}
className="rounded-2xl border-yellow-500 bg-yellow-50 p-1 text-yellow-800"
>
<button
type="button"
className="flex items-center space-x-1 px-1"
onClick={() =>
handleResetFilter(category as FiltersType, filterValue as FilterValues)
}
>
<span>{filterValue}</span>
<X className="h-4 w-4 text-yellow-400" />
</button>
</li>
)
)}
</ul>
</li>
))}
{Object.entries(filtersSettings).map(([category, filterValues]) => {
// Ensure filterValues is an array
const valuesArray = Array.isArray(filterValues) ? filterValues : [filterValues];
// Determine if there are more than 3 filter values for this category
const hasMoreThanThree = valuesArray.length > 3;
// Calculate remaining filters for this category if more than 3
const remainingFiltersCount = hasMoreThanThree ? valuesArray.length - 3 : 0;

return (
<li key={category}>
<ul className="flex flex-wrap items-center gap-1">
{valuesArray
.slice(0, 3) // Always slice to the first three for consistency
.map((filterValue) => (
<FiltersBadge
key={`${category}-${filterValue}`}
category={category as FiltersType}
filterValue={filterValue}
/>
))}
{hasMoreThanThree && (
<li key={`${category}-more`}>and {remainingFiltersCount} more</li>
)}
</ul>
</li>
);
})}
</ul>
</div>
)}
Expand Down
4 changes: 2 additions & 2 deletions client/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ __metadata:
lucide-react: ^0.252.0
mapbox-gl: 2.15.0
next: 14.1.0
nuqs: ^1.16.1
nuqs: 1.17.0
postcss: 8.4.24
prettier: ^2.8.8
prettier-plugin-tailwindcss: ^0.3.0
Expand Down Expand Up @@ -6416,7 +6416,7 @@ __metadata:
languageName: node
linkType: hard

"nuqs@npm:^1.16.1":
"nuqs@npm:1.17.0":
version: 1.17.0
resolution: "nuqs@npm:1.17.0"
dependencies:
Expand Down

0 comments on commit 912a76b

Please sign in to comment.