-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat(golden-ledger): add remote graphql schemas - smart-escrow xdai - dahouse stats xdai * fix _meta collision with prefix * chore(hasura): add docker auto-setup - switch to auto metadata/migration image - add setup container to auto-seed * fix(hasura): reload metadata after seeding data * chore(docker): update readme * Add TRANSACTIONS_QUERY * Update caniuse * Add useTransactions * Add data formatter for useTransactions * Add Accounting page * feat(tx-table): initial add * refactor(tx-table): remove chakra-ui/icons dep * fix(tx-table): fix column sorting * feat(tx-table): add 'days held' column * fix(SiteLayout.tsx): show {error.message} * fix(accounting): query hasura * Minor: add useBalances hook (#32) * Add moloch query * Add useBalances hook * Add namespace for daohaus_xdai * Pass transactions and balances as SiteLayout data * chore(hasura-setup): cut setup timeout to 1m * feat(accounting): add balances table * treasury_token_history table added (#33) Co-authored-by: Peter Sparacino <[email protected]> * Add useTokenPrices hook * txnID and symbol columns added (#34) * Minor: add price data to transactions table (#35) * Add price data to transactions table * Return "unknown value" if no price conversion * Fix typo * Add tabs and cell borders to accounting page (#36) * styling(accounting): style tab title * accounting page: add table filters (#37) * feat(accounting): add column filters (wip) * feat(table-filtering): fix date/number filter * fix(accounting): days-held filter * fix(accounting): update table style * feat(table-filtering): add enum type, tooltips * Don't get balances unless transactions are fetched * Minor tweaks * Tweak useAccounting error messages Co-authored-by: ECWireless <[email protected]> * Add pagination for DataTable (#40) * Add pagination for DataTable * Make input label dynamic * Accounting: link DAOhaus member profile from transactions table (#39) * feat(accounting): add column filters (wip) * feat(table-filtering): fix date/number filter * fix(accounting): days-held filter * fix(accounting): update table style * fixes (#38) * feat(table-filtering): add enum type, tooltips * feat(accounting): tx-table - add member link (wip) * fix(member-links): add daohaus profile link * feat(accounting): link DAOhaus member profile * refactor(BalancesTable): add aria-label * fix(chains): jsonRpcProvider setup post lib update * refactor(useMemberList): remove console.log * Remove unnecessary comment Co-authored-by: scottrepreneur <[email protected]> Co-authored-by: ECWireless <[email protected]> * Minor: improve accounting export data (#41) * Improve accounting error messages * Add accounting link to navbar * Improve export data formatting * Feature/add accounting page add current prices table (#42) * add current_token_prices table * updated field name * Improve accounting page loader (#43) Co-authored-by: Matthew O'Connell <[email protected]> Co-authored-by: psparacino <[email protected]> Co-authored-by: ECWireless <[email protected]> Co-authored-by: ECWireless <[email protected]> Co-authored-by: Peter Sparacino <[email protected]> Co-authored-by: Matthew O'Connell <[email protected]>
- Loading branch information
1 parent
85db615
commit 28752f9
Showing
44 changed files
with
3,578 additions
and
2,117 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { Link, Tooltip } from '@raidguild/design-system'; | ||
import { createColumnHelper } from '@tanstack/react-table'; | ||
import { ITokenBalanceLineItem } from '../types'; | ||
import { formatNumber, minMaxNumberFilter, sortNumeric } from '../utils'; | ||
import { DataTable } from './DataTable'; | ||
import TokenWithUsdValue from './TokenWithUsdValue'; | ||
|
||
interface BalancesTableProps { | ||
data: ITokenBalanceLineItem[]; | ||
} | ||
|
||
const columnHelper = createColumnHelper<ITokenBalanceLineItem>(); | ||
|
||
const columns = [ | ||
columnHelper.accessor('tokenExplorerLink', { | ||
id: 'tokenExplorerLink', | ||
cell: (info) => info.getValue(), | ||
header: 'Token Link', | ||
meta: { | ||
hidden: true, | ||
}, | ||
}), | ||
columnHelper.accessor('token.symbol', { | ||
id: 'tokenSymbol', | ||
cell: (info) => ( | ||
<Link | ||
href={info.row.getValue('tokenExplorerLink')} | ||
target='_blank' | ||
aria-label='tokenExplorerLink' | ||
> | ||
<Tooltip label='view token'>{info.getValue()}</Tooltip> | ||
</Link> | ||
), | ||
header: 'Token', | ||
meta: { | ||
dataType: 'enum', | ||
}, | ||
}), | ||
columnHelper.accessor('inflow.tokenValue', { | ||
cell: formatNumber, | ||
header: 'Inflow', | ||
meta: { | ||
dataType: 'numeric', | ||
}, | ||
filterFn: minMaxNumberFilter, | ||
sortingFn: sortNumeric, | ||
}), | ||
columnHelper.accessor('outflow.tokenValue', { | ||
cell: formatNumber, | ||
header: 'Outflow', | ||
meta: { | ||
dataType: 'numeric', | ||
}, | ||
filterFn: minMaxNumberFilter, | ||
sortingFn: sortNumeric, | ||
}), | ||
columnHelper.accessor('priceConversion', { | ||
id: 'priceConversion', | ||
cell: (info) => info.getValue(), | ||
header: 'Conversion', | ||
meta: { | ||
dataType: 'numeric', | ||
hidden: true, | ||
}, | ||
filterFn: minMaxNumberFilter, | ||
sortingFn: sortNumeric, | ||
}), | ||
columnHelper.accessor('closing.tokenValue', { | ||
cell: (info) => <TokenWithUsdValue info={info} />, | ||
header: 'Balance', | ||
meta: { | ||
dataType: 'numeric', | ||
}, | ||
filterFn: minMaxNumberFilter, | ||
sortingFn: sortNumeric, | ||
}), | ||
]; | ||
|
||
const BalancesTable = ({ data }: BalancesTableProps) => ( | ||
<DataTable | ||
id='balancesDataTable' | ||
columns={columns} | ||
data={data} | ||
sort={[{ id: 'tokenSymbol', desc: false }]} | ||
/> | ||
); | ||
|
||
export default BalancesTable; |
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,231 @@ | ||
import { useState } from 'react'; | ||
import { | ||
Box, | ||
Input, | ||
Select, | ||
Table, | ||
Tbody, | ||
Td, | ||
Th, | ||
Thead, | ||
ThemingProps, | ||
Tr, | ||
} from '@chakra-ui/react'; | ||
import { FiChevronDown, FiChevronUp } from 'react-icons/fi'; | ||
import { | ||
useReactTable, | ||
flexRender, | ||
ColumnFiltersState, | ||
getCoreRowModel, | ||
getFilteredRowModel, | ||
ColumnDef, | ||
SortingState, | ||
getSortedRowModel, | ||
RowData, | ||
getFacetedRowModel, | ||
getFacetedMinMaxValues, | ||
getFacetedUniqueValues, | ||
getPaginationRowModel, | ||
} from '@tanstack/react-table'; | ||
import Filter from './Filter'; | ||
import { Flex, Button, Text, TableContainer } from '@raidguild/design-system'; | ||
|
||
declare module '@tanstack/table-core' { | ||
interface ColumnMeta<TData extends RowData, TValue> { | ||
dataType?: 'numeric' | 'datetime' | 'enum' | 'string'; | ||
hidden?: boolean; | ||
} | ||
} | ||
|
||
export type DataTableProps<Data extends object> = ThemingProps & { | ||
id: string; | ||
data: Data[]; | ||
columns: ColumnDef<Data, unknown>[]; | ||
sort?: SortingState; | ||
}; | ||
|
||
export function DataTable<Data extends object>({ | ||
id, | ||
data, | ||
columns, | ||
sort = [], | ||
...props | ||
}: DataTableProps<Data>) { | ||
const [sorting, setSorting] = useState<SortingState>(sort); | ||
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]); | ||
const [columnVisibility, setColumnVisibility] = useState( | ||
Object.assign( | ||
{}, | ||
...columns.map((c) => ({ [c.id]: !c.meta?.hidden ?? true })) | ||
) | ||
); | ||
|
||
const table = useReactTable({ | ||
columns, | ||
data, | ||
getCoreRowModel: getCoreRowModel(), | ||
getFacetedRowModel: getFacetedRowModel(), | ||
getFacetedUniqueValues: getFacetedUniqueValues(), | ||
getFacetedMinMaxValues: getFacetedMinMaxValues(), | ||
getFilteredRowModel: getFilteredRowModel(), | ||
onSortingChange: setSorting, | ||
getSortedRowModel: getSortedRowModel(), | ||
onColumnFiltersChange: setColumnFilters, | ||
onColumnVisibilityChange: setColumnVisibility, | ||
state: { | ||
columnFilters, | ||
columnVisibility, | ||
sorting, | ||
}, | ||
initialState: { | ||
pagination: { | ||
pageSize: 20, | ||
pageIndex: 0, | ||
}, | ||
}, | ||
getPaginationRowModel: getPaginationRowModel(), | ||
// debugTable: true, | ||
// debugHeaders: true, | ||
// debugColumns: true, | ||
}); | ||
|
||
return ( | ||
<Box border='1px solid grey' borderRadius='4px'> | ||
<TableContainer maxWidth='90vw'> | ||
<Table id={id} {...props}> | ||
<Thead> | ||
{table.getHeaderGroups().map((headerGroup) => ( | ||
<Tr key={headerGroup.id}> | ||
{headerGroup.headers.map((header) => ( | ||
<Th | ||
key={header.id} | ||
isNumeric={ | ||
header.column.columnDef.meta?.dataType === 'numeric' | ||
} | ||
verticalAlign='top' | ||
borderBlock='1px solid gray' | ||
> | ||
<Flex | ||
justifyContent='space-between' | ||
verticalAlign='middle' | ||
onClick={header.column.getToggleSortingHandler()} | ||
_hover={{ cursor: 'pointer' }} | ||
> | ||
{flexRender( | ||
header.column.columnDef.header, | ||
header.getContext() | ||
)} | ||
{header.column.getIsSorted() ? ( | ||
header.column.getIsSorted() === 'desc' ? ( | ||
<FiChevronDown aria-label='sorted descending' /> | ||
) : ( | ||
<FiChevronUp aria-label='sorted ascending' /> | ||
) | ||
) : null} | ||
</Flex> | ||
{header.column.getCanFilter() ? ( | ||
<Box my='1'> | ||
<Filter column={header.column} /> | ||
</Box> | ||
) : null} | ||
</Th> | ||
))} | ||
</Tr> | ||
))} | ||
</Thead> | ||
<Tbody> | ||
{table.getRowModel().rows.map((row) => ( | ||
<Tr key={row.id}> | ||
{row.getVisibleCells().map((cell) => ( | ||
<Td | ||
key={cell.id} | ||
isNumeric={ | ||
cell.column.columnDef.meta?.dataType === 'numeric' | ||
} | ||
borderBlock='1px solid gray' | ||
fontFamily='mono' | ||
> | ||
{flexRender(cell.column.columnDef.cell, cell.getContext())} | ||
</Td> | ||
))} | ||
</Tr> | ||
))} | ||
</Tbody> | ||
</Table> | ||
</TableContainer> | ||
|
||
<Flex align='center' justifyContent='space-between'> | ||
<Flex align='center' gap='24px'> | ||
<Flex> | ||
<Button | ||
variant='link' | ||
onClick={() => table.setPageIndex(0)} | ||
disabled={!table.getCanPreviousPage()} | ||
> | ||
{'<<'} | ||
</Button> | ||
<Button | ||
variant='link' | ||
onClick={() => table.previousPage()} | ||
disabled={!table.getCanPreviousPage()} | ||
> | ||
{'<'} | ||
</Button> | ||
<Button | ||
variant='link' | ||
onClick={() => table.nextPage()} | ||
disabled={!table.getCanNextPage()} | ||
> | ||
{'>'} | ||
</Button> | ||
<Button | ||
variant='link' | ||
onClick={() => table.setPageIndex(table.getPageCount() - 1)} | ||
disabled={!table.getCanNextPage()} | ||
> | ||
{'>>'} | ||
</Button> | ||
</Flex> | ||
<Flex gap='12px'> | ||
<Text>Page</Text> | ||
<Text> | ||
<strong> | ||
{table.getState().pagination.pageIndex + 1} of{' '} | ||
{table.getPageCount()} | ||
</strong> | ||
</Text> | ||
</Flex> | ||
<Box>|</Box> | ||
<Flex align='center' gap='12px'> | ||
<label htmlFor={`table-go-to-page-${id}`}> | ||
<Text>Go to page:</Text> | ||
</label> | ||
<Input | ||
id={`table-go-to-page-${id}`} | ||
type='number' | ||
defaultValue={table.getState().pagination.pageIndex + 1} | ||
maxWidth='80px' | ||
onChange={(e) => { | ||
const page = e.target.value ? Number(e.target.value) - 1 : 0; | ||
table.setPageIndex(page); | ||
}} | ||
/> | ||
</Flex> | ||
</Flex> | ||
<Select | ||
value={table.getState().pagination.pageSize} | ||
onChange={(e) => { | ||
table.setPageSize(Number(e.target.value)); | ||
}} | ||
maxWidth='150px' | ||
> | ||
{[20, 50, 100, 200].map((pageSize) => ( | ||
<option key={pageSize} value={pageSize}> | ||
Show {pageSize} | ||
</option> | ||
))} | ||
</Select> | ||
</Flex> | ||
</Box> | ||
); | ||
} |
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,40 @@ | ||
import { useEffect, useState } from 'react'; | ||
import { Input, InputProps } from '@chakra-ui/react'; | ||
|
||
type DebouncedInputProps<T extends string | number> = { | ||
value: T; | ||
onChange: (value: T) => void; | ||
debounce?: number; | ||
} & Omit<InputProps, 'onChange'>; | ||
|
||
// A debounced input react component | ||
const DebouncedInput = <T extends string | number>({ | ||
value: initialValue, | ||
onChange, | ||
debounce = 500, | ||
...props | ||
}: DebouncedInputProps<T>) => { | ||
const [value, setValue] = useState(initialValue); | ||
|
||
useEffect(() => { | ||
setValue(initialValue); | ||
}, [initialValue]); | ||
|
||
useEffect(() => { | ||
const timeout = setTimeout(() => { | ||
onChange(value); | ||
}, debounce); | ||
|
||
return () => clearTimeout(timeout); | ||
}, [debounce, onChange, value]); | ||
|
||
return ( | ||
<Input | ||
{...props} | ||
value={value} | ||
onChange={(e) => setValue(e.target.value as T)} | ||
/> | ||
); | ||
}; | ||
|
||
export default DebouncedInput; |
Oops, something went wrong.