diff options
author | eug-vs <eug-vs@keemail.me> | 2021-04-17 11:33:32 +0300 |
---|---|---|
committer | eug-vs <eug-vs@keemail.me> | 2021-04-17 11:33:32 +0300 |
commit | f0e470472a16957217b091489afdab2006719294 (patch) | |
tree | dfb177a6272bf59a5f3ce3f5680f5b1b8fbce984 | |
parent | 27f51e35bf732667e4e6015fb76f7fd6871e41cd (diff) | |
download | commercel-ui-f0e470472a16957217b091489afdab2006719294.tar.gz |
feat: add sort to ListTable
-rw-r--r-- | src/components/ListTable.tsx | 35 | ||||
-rw-r--r-- | src/lib/ServiceList.tsx | 3 |
2 files changed, 31 insertions, 7 deletions
diff --git a/src/components/ListTable.tsx b/src/components/ListTable.tsx index 89a2e06..e90d2db 100644 --- a/src/components/ListTable.tsx +++ b/src/components/ListTable.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState, useMemo, useCallback } from 'react'; import _ from 'lodash'; export interface Field { @@ -10,9 +10,14 @@ export interface Field { interface Props<T = any> { items?: T[]; fields: Field[]; - handleRowClick?: (index: number) => void; + handleRowClick?: (item: T, index?: number) => void; } +const sortLabels = { + asc: '^', + desc: 'v', +}; + const getItemField = (item: any, field: Field) => { const value = _.get(item, field.key); return field.transform ? field.transform(value) : value; @@ -20,20 +25,40 @@ const getItemField = (item: any, field: Field) => { const ListTable: React.FC<Props> = ({ items = [], fields, handleRowClick = () => {} }) => { + const [sortBy, setSortBy] = useState<string>(''); + const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc'); + + const sortedItems = useMemo(() => { + const result = _.sortBy(items, sortBy); + if (sortOrder === 'asc') result.reverse(); + return result; + }, [items, sortBy, sortOrder]); + + const handleFieldClick = useCallback((field: Field) => { + if (sortBy === field.key) setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc'); + else setSortOrder('desc'); + setSortBy(field.key); + }, [sortBy, sortOrder]); + if (!items.length) return <div className="text-center p-6">No data</div>; + return ( <table className="table-auto w-full"> <thead> <tr className="border-b select-none"> - {fields.map(field => <th className="pl-3 text-left bg-gray-100" key={field.label}>{field.label}</th>)} + {fields.map(field => ( + <th className="pl-3 text-left bg-gray-100" key={field.label} onClick={() => handleFieldClick(field)}> + {field.label} {field.key === sortBy && sortLabels[sortOrder]} + </th> + ))} </tr> </thead> <tbody> - {items.map((item, index) => ( + {sortedItems.map((item, index) => ( <tr key={item._id} className={`border-b hover:bg-gray-100 cursor-pointer ${index % 2 && 'bg-gray-50'}`} - onClick={() => handleRowClick(index)} + onClick={() => handleRowClick(item, index)} > {fields.map(field => ( <td key={`${item._id} ${field.label}`} className="p-3"> diff --git a/src/lib/ServiceList.tsx b/src/lib/ServiceList.tsx index 74ad10b..e7015ae 100644 --- a/src/lib/ServiceList.tsx +++ b/src/lib/ServiceList.tsx @@ -16,8 +16,7 @@ const ServiceList: React.FC = () => { route: `/${service.route}/add${location.search}`, }]; - const handleRowClick = (index: number) => { - const item = data && data[index]; + const handleRowClick = (item: any) => { const route = service.rowLink ? service.rowLink(item) : `/${service.route}/${item?._id}`; |