diff options
Diffstat (limited to 'src/components/ListTable.tsx')
-rw-r--r-- | src/components/ListTable.tsx | 35 |
1 files changed, 30 insertions, 5 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"> |