-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1447 from Vizzuality/MRXN23-284-inventory-panel-l…
…ist-v2-new [MRXN23-284]: Unify lists for features / protected areas / cost surface
- Loading branch information
Showing
31 changed files
with
667 additions
and
1,166 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
.../project/sidebar/project/inventory-panel/components/inventory-table/header-item/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { useCallback } from 'react'; | ||
|
||
import { ArrowDown, ArrowUp } from 'lucide-react'; | ||
|
||
import { cn } from 'utils/cn'; | ||
|
||
import { HeaderItem } from './types'; | ||
|
||
const HeaderItem = ({ | ||
className, | ||
text, | ||
name, | ||
columns, | ||
sorting, | ||
onClick, | ||
}: HeaderItem): JSX.Element => { | ||
const sortingMatches = /^(-?)(.+)$/.exec(sorting); | ||
const sortField = sortingMatches[2]; | ||
const sortOrder = sortingMatches[1] === '-' ? 'desc' : 'asc'; | ||
|
||
const isActive = columns[name] === sortField; | ||
|
||
const handleClick = useCallback(() => { | ||
onClick(columns[name]); | ||
}, [onClick, columns, name]); | ||
|
||
return ( | ||
<button | ||
type="button" | ||
className={cn({ | ||
'inline-flex items-center space-x-2': true, | ||
[className]: !!className, | ||
})} | ||
onClick={handleClick} | ||
> | ||
<span | ||
className={cn({ | ||
'text-xs font-semibold uppercase leading-none text-gray-400': true, | ||
'text-white': isActive, | ||
[className]: !!className, | ||
})} | ||
> | ||
{text} | ||
</span> | ||
{sortOrder === 'asc' && isActive ? ( | ||
<ArrowDown className={isActive ? 'text-blue-400' : 'text-gray-400'} size={20} /> | ||
) : ( | ||
<ArrowUp className={isActive ? 'text-blue-400' : 'text-gray-400'} size={20} /> | ||
)} | ||
</button> | ||
); | ||
}; | ||
|
||
export default HeaderItem; |
10 changes: 10 additions & 0 deletions
10
...t/project/sidebar/project/inventory-panel/components/inventory-table/header-item/types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export type HeaderItem = { | ||
className?: string; | ||
text: string; | ||
name: string; | ||
columns: { | ||
[key: string]: string; | ||
}; | ||
sorting: string; | ||
onClick?: (field: string) => void; | ||
}; |
87 changes: 87 additions & 0 deletions
87
app/layout/project/sidebar/project/inventory-panel/components/inventory-table/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import Checkbox from 'components/forms/checkbox'; | ||
import Loading from 'components/loading'; | ||
|
||
import HeaderItem from './header-item'; | ||
import RowItem from './row-item'; | ||
import { InventoryTable } from './types'; | ||
|
||
const InventoryTable = ({ | ||
loading, | ||
data, | ||
noDataMessage, | ||
columns, | ||
sorting, | ||
selectedIds, | ||
onSortChange, | ||
onToggleSeeOnMap, | ||
onSelectRow, | ||
onSelectAll, | ||
ActionsComponent, | ||
}: InventoryTable): JSX.Element => { | ||
const noData = !loading && data?.length === 0; | ||
|
||
return ( | ||
<> | ||
{loading && !data.length && ( | ||
<div className="relative min-h-[200px]"> | ||
<Loading | ||
visible={true} | ||
className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" | ||
/> | ||
</div> | ||
)} | ||
{noData && <div className="flex h-[200px] items-center justify-center">{noDataMessage}</div>} | ||
{!!data?.length && ( | ||
<table className="w-full table-auto space-y-2"> | ||
<thead className="text-left text-xs font-semibold uppercase"> | ||
<tr className="flex w-full items-center pl-1"> | ||
<th> | ||
<Checkbox | ||
id="select-all" | ||
theme="light" | ||
className="block h-4 w-4 checked:bg-blue-400" | ||
onChange={onSelectAll} | ||
/> | ||
</th> | ||
<th className="flex-1 pl-2"> | ||
<HeaderItem | ||
text={'Name'} | ||
name={'name'} | ||
columns={columns} | ||
sorting={sorting} | ||
onClick={onSortChange} | ||
/> | ||
</th> | ||
<th className="flex flex-1 justify-start py-2 pl-14"> | ||
<HeaderItem | ||
className="justify-center" | ||
text={'Type'} | ||
name={'tag'} | ||
columns={columns} | ||
sorting={sorting} | ||
onClick={onSortChange} | ||
/> | ||
</th> | ||
</tr> | ||
</thead> | ||
<tbody className="block max-h-[calc(100vh-430px)] divide-y divide-gray-400 overflow-y-auto overflow-x-hidden pl-1 align-baseline text-sm"> | ||
{data.map((item) => ( | ||
<RowItem | ||
key={item.id} | ||
item={item} | ||
selectedIds={selectedIds} | ||
onSelectRow={onSelectRow} | ||
onToggleSeeOnMap={onToggleSeeOnMap} | ||
ActionsComponent={ActionsComponent} | ||
/> | ||
))} | ||
</tbody> | ||
</table> | ||
)} | ||
</> | ||
); | ||
}; | ||
|
||
export { type DataItem } from './types'; | ||
|
||
export default InventoryTable; |
85 changes: 85 additions & 0 deletions
85
...out/project/sidebar/project/inventory-panel/components/inventory-table/row-item/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { MoreHorizontal } from 'lucide-react'; | ||
|
||
import Checkbox from 'components/forms/checkbox'; | ||
import Icon from 'components/icon'; | ||
import { Popover, PopoverContent, PopoverTrigger } from 'components/popover'; | ||
import { cn } from 'utils/cn'; | ||
|
||
import HIDE_SVG from 'svgs/ui/hide.svg?sprite'; | ||
import SHOW_SVG from 'svgs/ui/show.svg?sprite'; | ||
|
||
import { RowItem } from './types'; | ||
|
||
const RowItem = ({ | ||
item, | ||
selectedIds, | ||
onSelectRow, | ||
onToggleSeeOnMap, | ||
ActionsComponent, | ||
}: RowItem) => { | ||
const { id, name, scenarios, tag, isVisibleOnMap } = item; | ||
|
||
return ( | ||
<tr key={id} className="align-top"> | ||
<td className="pb-2 pr-1 pt-5"> | ||
<Checkbox | ||
id={`select-${id}`} | ||
theme="light" | ||
className="block h-4 w-4 checked:bg-blue-400" | ||
onChange={onSelectRow} | ||
value={id} | ||
checked={selectedIds.includes(id)} | ||
/> | ||
</td> | ||
<td className="px-1 pb-2 pt-5"> | ||
<span className="inline-flex">{name}</span> | ||
<div className="mt-1.5 text-xs text-gray-300"> | ||
Currently in use in | ||
<span className="rounded bg-blue-500 bg-opacity-10 px-1 text-blue-500"> | ||
{scenarios} | ||
</span>{' '} | ||
scenarios. | ||
</div> | ||
</td> | ||
<td className="px-6 pb-2 pt-5 text-xs"> | ||
{tag && ( | ||
<div className="flex justify-center"> | ||
<span className="whitespace-nowrap rounded-full bg-yellow-600 bg-opacity-10 px-2 py-1 text-yellow-600"> | ||
{tag} | ||
</span> | ||
</div> | ||
)} | ||
</td> | ||
<td className="pb-2 pl-1 pr-2 pt-5"> | ||
<div className="flex gap-6"> | ||
<button type="button" onClick={() => onToggleSeeOnMap(id)}> | ||
<Icon | ||
className={cn({ | ||
'h-5 w-5 text-gray-400': true, | ||
'text-blue-400': isVisibleOnMap, | ||
})} | ||
icon={isVisibleOnMap ? SHOW_SVG : HIDE_SVG} | ||
/> | ||
</button> | ||
<Popover> | ||
<PopoverTrigger asChild> | ||
<button type="button" className="h-5 w-5"> | ||
<MoreHorizontal className="h-4 w-4 text-white" /> | ||
</button> | ||
</PopoverTrigger> | ||
<PopoverContent | ||
className="w-auto rounded-2xl border-transparent p-0" | ||
side="bottom" | ||
sideOffset={5} | ||
align="start" | ||
> | ||
<ActionsComponent item={item} /> | ||
</PopoverContent> | ||
</Popover> | ||
</div> | ||
</td> | ||
</tr> | ||
); | ||
}; | ||
|
||
export default RowItem; |
11 changes: 11 additions & 0 deletions
11
...yout/project/sidebar/project/inventory-panel/components/inventory-table/row-item/types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { ChangeEvent } from 'react'; | ||
|
||
import { DataItem } from '../types'; | ||
|
||
export type RowItem = { | ||
item: DataItem; | ||
selectedIds: string[]; | ||
onSelectRow: (evt: ChangeEvent<HTMLInputElement>) => void; | ||
onToggleSeeOnMap: (id: string) => void; | ||
ActionsComponent: ({ item }) => JSX.Element; | ||
}; |
25 changes: 25 additions & 0 deletions
25
app/layout/project/sidebar/project/inventory-panel/components/inventory-table/types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { ChangeEvent } from 'react'; | ||
|
||
export type DataItem = { | ||
id: string; | ||
name: string; | ||
scenarios: number; | ||
tag: string; | ||
isVisibleOnMap: boolean; | ||
}; | ||
|
||
export type InventoryTable = { | ||
loading: boolean; | ||
data: DataItem[]; | ||
noDataMessage: string; | ||
columns: { | ||
[key: string]: string; | ||
}; | ||
sorting: string; | ||
selectedIds: string[]; | ||
onSortChange: (field: string) => void; | ||
onToggleSeeOnMap: (id: string) => void; | ||
onSelectRow: (evt: ChangeEvent<HTMLInputElement>) => void; | ||
onSelectAll: (evt: ChangeEvent<HTMLInputElement>) => void; | ||
ActionsComponent: ({ item }) => JSX.Element; | ||
}; |
37 changes: 37 additions & 0 deletions
37
app/layout/project/sidebar/project/inventory-panel/constants.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { NavigationInventoryTabs } from 'layout/project/navigation/types'; | ||
|
||
import CostSurfaceTable from './cost-surface'; | ||
import CostSurfaceInfo from './cost-surface/info'; | ||
import FeaturesTable from './features'; | ||
import FeaturesInfo from './features/info'; | ||
import FeatureUploadModal from './features/modals/upload'; | ||
import ProtectedAreasTable from './protected-areas'; | ||
import ProtectedAreasFooter from './protected-areas/footer'; | ||
import { InventoryPanel } from './types'; | ||
|
||
export const INVENTORY_TABS = { | ||
'protected-areas': { | ||
title: 'Protected Areas', | ||
search: 'Search protected areas', | ||
noData: 'No protected areas found.', | ||
TableComponent: ProtectedAreasTable, | ||
FooterComponent: ProtectedAreasFooter, | ||
}, | ||
'cost-surface': { | ||
title: 'Cost Surface', | ||
search: 'Search cost surfaces', | ||
noData: 'No cost surfaces found.', | ||
InfoComponent: CostSurfaceInfo, | ||
TableComponent: CostSurfaceTable, | ||
}, | ||
features: { | ||
title: 'Features', | ||
search: 'Search features', | ||
noData: 'No features found.', | ||
InfoComponent: FeaturesInfo, | ||
UploadModalComponent: FeatureUploadModal, | ||
TableComponent: FeaturesTable, | ||
}, | ||
} satisfies { | ||
[key in NavigationInventoryTabs]: InventoryPanel; | ||
}; |
6 changes: 2 additions & 4 deletions
6
app/layout/project/sidebar/project/inventory-panel/cost-surface/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,5 @@ | ||
import Section from 'layout/section'; | ||
|
||
const InventoryPanelCostSurface = (): JSX.Element => { | ||
return <Section>InventoryPanelCostSurface</Section>; | ||
const InventoryPanelCostSurface = ({ noData: noDataMessage }: { noData: string }): JSX.Element => { | ||
return <div className="flex h-[200px] items-center justify-center">{noDataMessage}</div>; | ||
}; | ||
|
||
export default InventoryPanelCostSurface; |
28 changes: 28 additions & 0 deletions
28
app/layout/project/sidebar/project/inventory-panel/cost-surface/info/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import COST_LAND_IMG from 'images/info-buttons/img_cost_surface_marine.png'; | ||
import COST_SEA_IMG from 'images/info-buttons/img_cost_surface_terrestrial.png'; | ||
|
||
const CostSurfaceInfo = (): JSX.Element => { | ||
return ( | ||
<> | ||
<h4 className="mb-2.5 font-heading text-lg">What is a Cost Surface?</h4> | ||
<div className="space-y-2"> | ||
<p> | ||
Marxan aims to minimize socio-economic impacts and conflicts between uses through what is | ||
called the “cost” surface. In conservation planning, cost data may reflect acquisition, | ||
management, or opportunity costs ($), but may also reflect non-monetary impacts. Proxies | ||
are commonly used in absence of fine-scale socio-economic information. A default value for | ||
cost will be the planning unit area but you can upload your cost surface. | ||
</p> | ||
<p> | ||
In the examples below, we illustrate how distance from a city, road or port can be used as | ||
a proxy cost surface. In these examples, areas with many competing activities will make a | ||
planning unit cost more than areas further away with less competition for access. | ||
</p> | ||
<img src={COST_SEA_IMG} alt="Cost sea" /> | ||
<img src={COST_LAND_IMG} alt="Cost Land" /> | ||
</div> | ||
</> | ||
); | ||
}; | ||
|
||
export default CostSurfaceInfo; |
Oops, something went wrong.