Commit 1ca78283 authored by isstuev's avatar isstuev

new version of sticky, probably final

parent 1a974c78
......@@ -16,7 +16,9 @@ export default function useScrollDirection() {
const currentScrollPosition = clamp(window.pageYOffset, 0, window.document.body.scrollHeight - window.innerHeight);
const scrollDiff = currentScrollPosition - prevScrollPosition.current;
if (Math.abs(scrollDiff) > SCROLL_DIFF_THRESHOLD) {
if (window.pageYOffset === 0) {
setDirection(undefined);
} else if (Math.abs(scrollDiff) > SCROLL_DIFF_THRESHOLD) {
setDirection(scrollDiff < 0 ? 'up' : 'down');
}
......
......@@ -16,10 +16,10 @@ const variantSimple = definePartsStyle((props) => {
th: {
border: 0,
color: mode('gray.600', 'whiteAlpha.700')(props),
backgroundColor: mode('blackAlpha.100', 'whiteAlpha.200')(props),
...transitionProps,
},
thead: {
backgroundColor: mode('blackAlpha.100', 'whiteAlpha.200')(props),
...transitionProps,
},
td: {
......@@ -73,9 +73,6 @@ const variants = {
};
const baseStyle = definePartsStyle({
thead: {
backgroundColor: 'gray.50',
},
th: {
textTransform: 'none',
fontFamily: 'body',
......@@ -83,6 +80,12 @@ const baseStyle = definePartsStyle({
overflow: 'hidden',
color: 'gray.500',
letterSpacing: 'none',
_first: {
borderTopLeftRadius: '8px',
},
_last: {
borderTopRightRadius: '8px',
},
},
td: {
fontSize: 'md',
......@@ -92,7 +95,7 @@ const baseStyle = definePartsStyle({
tableLayout: 'fixed',
borderTopLeftRadius: 'base',
borderTopRightRadius: 'base',
overflow: 'hidden',
overflow: 'unset',
fontVariant: 'normal',
},
});
......
import React from 'react';
const ScrollDirectionContext = React.createContext<'up' | 'down' | undefined>(undefined);
export default ScrollDirectionContext;
......@@ -4,7 +4,6 @@ import {
Tbody,
Tr,
Th,
TableContainer,
} from '@chakra-ui/react';
import React from 'react';
......@@ -21,26 +20,24 @@ interface Props {
const ApiKeyTable = ({ data, onDeleteClick, onEditClick, limit }: Props) => {
return (
<TableContainer width="100%">
<Table variant="simple" minWidth="600px">
<Thead>
<Tr>
<Th>{ `API key token (limit ${ limit } keys)` }</Th>
<Th width="108px"></Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item) => (
<ApiKeyTableItem
item={ item }
key={ item.api_key }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
/>
)) }
</Tbody>
</Table>
</TableContainer>
<Table variant="simple" minWidth="600px">
<Thead>
<Tr>
<Th>{ `API key token (limit ${ limit } keys)` }</Th>
<Th width="108px"></Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item) => (
<ApiKeyTableItem
item={ item }
key={ item.api_key }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
/>
)) }
</Tbody>
</Table>
);
};
......
import { Table, Thead, Tbody, Tr, Th, TableContainer } from '@chakra-ui/react';
import { Table, Thead, Tbody, Tr, Th } from '@chakra-ui/react';
import { AnimatePresence } from 'framer-motion';
import capitalize from 'lodash/capitalize';
import React from 'react';
......@@ -16,27 +16,25 @@ interface Props {
const BlocksTable = ({ data }: Props) => {
return (
<TableContainer width="100%" mt={ 8 }>
<Table variant="simple" minWidth="1040px" size="md" fontWeight={ 500 }>
<Thead>
<Tr>
<Th width="125px">Block</Th>
<Th width="120px">Size</Th>
<Th width="21%" minW="144px">{ capitalize(getNetworkValidatorTitle()) }</Th>
<Th width="64px" isNumeric>Txn</Th>
<Th width="35%">Gas used</Th>
<Th width="22%">Reward { appConfig.network.currency.symbol }</Th>
<Th width="22%">Burnt fees { appConfig.network.currency.symbol }</Th>
</Tr>
</Thead>
<Tbody>
<AnimatePresence initial={ false }>
{ /* TODO prop "enableTimeIncrement" should be set to false for second and later pages */ }
{ data.map((item) => <BlocksTableItem key={ item.height } data={ item } enableTimeIncrement/>) }
</AnimatePresence>
</Tbody>
</Table>
</TableContainer>
<Table variant="simple" minWidth="1040px" size="md" fontWeight={ 500 } mt={ 8 }>
<Thead>
<Tr>
<Th width="125px">Block</Th>
<Th width="120px">Size</Th>
<Th width="21%" minW="144px">{ capitalize(getNetworkValidatorTitle()) }</Th>
<Th width="64px" isNumeric>Txn</Th>
<Th width="35%">Gas used</Th>
<Th width="22%">Reward { appConfig.network.currency.symbol }</Th>
<Th width="22%">Burnt fees { appConfig.network.currency.symbol }</Th>
</Tr>
</Thead>
<Tbody>
<AnimatePresence initial={ false }>
{ /* TODO prop "enableTimeIncrement" should be set to false for second and later pages */ }
{ data.map((item) => <BlocksTableItem key={ item.height } data={ item } enableTimeIncrement/>) }
</AnimatePresence>
</Tbody>
</Table>
);
};
......
......@@ -4,7 +4,6 @@ import {
Tbody,
Tr,
Th,
TableContainer,
} from '@chakra-ui/react';
import React from 'react';
......@@ -20,26 +19,24 @@ interface Props {
const CustomAbiTable = ({ data, onDeleteClick, onEditClick }: Props) => {
return (
<TableContainer width="100%">
<Table variant="simple" minWidth="600px">
<Thead>
<Tr>
<Th>ABI for Smart contract address (0x...)</Th>
<Th width="108px"></Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item) => (
<CustomAbiTableItem
item={ item }
key={ item.id }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
/>
)) }
</Tbody>
</Table>
</TableContainer>
<Table variant="simple" minWidth="600px">
<Thead>
<Tr>
<Th>ABI for Smart contract address (0x...)</Th>
<Th width="108px"></Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item) => (
<CustomAbiTableItem
item={ item }
key={ item.id }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
/>
)) }
</Tbody>
</Table>
);
};
......
......@@ -4,7 +4,6 @@ import {
Tbody,
Tr,
Th,
TableContainer,
} from '@chakra-ui/react';
import React from 'react';
......@@ -20,27 +19,25 @@ interface Props {
const AddressTagTable = ({ data, onDeleteClick, onEditClick }: Props) => {
return (
<TableContainer width="100%">
<Table variant="simple" minWidth="600px">
<Thead>
<Tr>
<Th width="60%">Address</Th>
<Th width="40%">Private tag</Th>
<Th width="108px"></Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item: AddressTag) => (
<AddressTagTableItem
item={ item }
key={ item.id }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
/>
)) }
</Tbody>
</Table>
</TableContainer>
<Table variant="simple" minWidth="600px">
<Thead>
<Tr>
<Th width="60%">Address</Th>
<Th width="40%">Private tag</Th>
<Th width="108px"></Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item: AddressTag) => (
<AddressTagTableItem
item={ item }
key={ item.id }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
/>
)) }
</Tbody>
</Table>
);
};
......
......@@ -4,7 +4,6 @@ import {
Tbody,
Tr,
Th,
TableContainer,
} from '@chakra-ui/react';
import React from 'react';
......@@ -20,27 +19,25 @@ interface Props {
const AddressTagTable = ({ data, onDeleteClick, onEditClick }: Props) => {
return (
<TableContainer width="100%">
<Table variant="simple" minWidth="600px">
<Thead>
<Tr>
<Th width="75%">Transaction</Th>
<Th width="25%">Private tag</Th>
<Th width="108px"></Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item) => (
<TransactionTagTableItem
item={ item }
key={ item.id }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
/>
)) }
</Tbody>
</Table>
</TableContainer>
<Table variant="simple" minWidth="600px">
<Thead>
<Tr>
<Th width="75%">Transaction</Th>
<Th width="25%">Private tag</Th>
<Th width="108px"></Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item) => (
<TransactionTagTableItem
item={ item }
key={ item.id }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
/>
)) }
</Tbody>
</Table>
);
};
......
......@@ -4,7 +4,6 @@ import {
Tbody,
Tr,
Th,
TableContainer,
} from '@chakra-ui/react';
import React from 'react';
......@@ -20,28 +19,26 @@ interface Props {
const PublicTagTable = ({ data, onEditClick, onDeleteClick }: Props) => {
return (
<TableContainer width="100%">
<Table variant="simple" minWidth="600px">
<Thead>
<Tr>
<Th width="50%">Smart contract / Address (0x...)</Th>
<Th width="25%">Public tag</Th>
<Th width="25%">Request status</Th>
<Th width="108px"></Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item) => (
<PublicTagTableItem
item={ item }
key={ item.id }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
/>
)) }
</Tbody>
</Table>
</TableContainer>
<Table variant="simple" minWidth="600px">
<Thead>
<Tr>
<Th width="50%">Smart contract / Address (0x...)</Th>
<Th width="25%">Public tag</Th>
<Th width="25%">Request status</Th>
<Th width="108px"></Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item) => (
<PublicTagTableItem
item={ item }
key={ item.id }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
/>
)) }
</Tbody>
</Table>
);
};
......
......@@ -6,6 +6,8 @@ import { QueryKeys } from 'types/client/queries';
import * as cookies from 'lib/cookies';
import useFetch from 'lib/hooks/useFetch';
import useScrollDirection from 'lib/hooks/useScrollDirection';
import ScrollDirectionContext from 'ui/ScrollDirectionContext';
import PageContent from 'ui/shared/Page/PageContent';
import Header from 'ui/snippets/header/Header';
import NavigationDesktop from 'ui/snippets/navigation/NavigationDesktop';
......@@ -23,18 +25,22 @@ const Page = ({ children, wrapChildren = true, hideMobileHeaderOnScrollDown }: P
enabled: Boolean(cookies.get(cookies.NAMES.API_TOKEN)),
});
const directionContext = useScrollDirection();
const renderedChildren = wrapChildren ? (
<PageContent>{ children }</PageContent>
) : children;
return (
<Flex w="100%" minH="100vh" alignItems="stretch">
<NavigationDesktop/>
<Flex flexDir="column" width="100%">
<Header hideOnScrollDown={ hideMobileHeaderOnScrollDown }/>
{ renderedChildren }
<ScrollDirectionContext.Provider value={ directionContext }>
<Flex w="100%" minH="100vh" alignItems="stretch">
<NavigationDesktop/>
<Flex flexDir="column" width="100%">
<Header hideOnScrollDown={ hideMobileHeaderOnScrollDown }/>
{ renderedChildren }
</Flex>
</Flex>
</Flex>
</ScrollDirectionContext.Provider>
);
};
......
import { Thead, useColorModeValue } from '@chakra-ui/react';
import type { TableHeadProps, PositionProps } from '@chakra-ui/react';
import throttle from 'lodash/throttle';
import React from 'react';
interface Props extends TableHeadProps {
top?: number;
children?: React.ReactNode;
}
const TheadSticky = ({ top, children, ...restProps }: Props) => {
const ref = React.useRef<HTMLTableSectionElement>(null);
const [ isSticky, setIsSticky ] = React.useState(false);
const handleScroll = React.useCallback(() => {
if (Number(ref.current?.getBoundingClientRect().y) <= (top || 0)) {
setIsSticky(true);
} else {
setIsSticky(false);
}
}, [ top ]);
React.useEffect(() => {
const throttledHandleScroll = throttle(handleScroll, 300);
window.addEventListener('scroll', throttledHandleScroll);
return () => {
window.removeEventListener('scroll', throttledHandleScroll);
};
}, [ handleScroll ]);
const props = {
...restProps,
position: 'sticky' as PositionProps['position'],
top: `${ top }px` || 0,
backgroundColor: useColorModeValue('white', 'black'),
boxShadow: isSticky ? 'md' : 'none',
};
return (
<Thead { ...props } ref={ ref }>
{ children }
</Thead>
);
};
export default TheadSticky;
import { HStack, Box, Flex, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import useScrollDirection from 'lib/hooks/useScrollDirection';
import ScrollDirectionContext from 'ui/ScrollDirectionContext';
import NetworkLogo from 'ui/snippets/networkMenu/NetworkLogo';
import ProfileMenuDesktop from 'ui/snippets/profileMenu/ProfileMenuDesktop';
import ProfileMenuMobile from 'ui/snippets/profileMenu/ProfileMenuMobile';
......@@ -11,52 +11,52 @@ import Burger from './Burger';
import ColorModeToggler from './ColorModeToggler';
const Header = ({ hideOnScrollDown }: {hideOnScrollDown?: boolean}) => {
const scrollDirection = useScrollDirection();
const bgColor = useColorModeValue('white', 'black');
const transform = hideOnScrollDown && scrollDirection === 'down' ? 'translateY(-60px)' : 'translateY(0)';
return (
<>
<Box bgColor={ bgColor } display={{ base: 'block', lg: 'none' }}>
<Flex
as="header"
position="fixed"
top={ 0 }
left={ 0 }
paddingX={ 4 }
paddingY={ 2 }
bgColor={ bgColor }
width="100%"
alignItems="center"
justifyContent="space-between"
zIndex="sticky2"
transform={ transform }
transitionProperty="transform,box-shadow"
transitionDuration="slow"
boxShadow={ scrollDirection === 'down' ? 'md' : 'none' }
>
<Burger/>
<NetworkLogo/>
<ProfileMenuMobile/>
</Flex>
<SearchBar/>
</Box>
<HStack
as="header"
width="100%"
alignItems="center"
justifyContent="center"
gap={ 12 }
display={{ base: 'none', lg: 'flex' }}
paddingX={ 12 }
paddingTop={ 9 }
paddingBottom="52px"
>
<SearchBar/>
<ColorModeToggler/>
<ProfileMenuDesktop/>
</HStack>
</>
<ScrollDirectionContext.Consumer>
{ (scrollDirection) => (
<>
<Box bgColor={ bgColor } display={{ base: 'block', lg: 'none' }}>
<Flex
as="header"
position="fixed"
top={ 0 }
left={ 0 }
paddingX={ 4 }
paddingY={ 2 }
bgColor={ bgColor }
width="100%"
alignItems="center"
justifyContent="space-between"
zIndex="sticky2"
transitionProperty="box-shadow"
transitionDuration="slow"
boxShadow={ !hideOnScrollDown && scrollDirection === 'down' ? 'md' : 'none' }
>
<Burger/>
<NetworkLogo/>
<ProfileMenuMobile/>
</Flex>
<SearchBar withShadow={ !hideOnScrollDown }/>
</Box><HStack
as="header"
width="100%"
alignItems="center"
justifyContent="center"
gap={ 12 }
display={{ base: 'none', lg: 'flex' }}
paddingX={ 12 }
paddingTop={ 9 }
paddingBottom="52px"
>
<SearchBar/>
<ColorModeToggler/>
<ProfileMenuDesktop/>
</HStack>
</>
) }
</ScrollDirectionContext.Consumer>
);
};
......
......@@ -6,7 +6,7 @@ import link from 'lib/link/link';
import SearchBarDesktop from './SearchBarDesktop';
import SearchBarMobile from './SearchBarMobile';
const SearchBar = () => {
const SearchBar = ({ withShadow }: {withShadow?: boolean}) => {
const [ value, setValue ] = React.useState('');
const handleChange = React.useCallback((event: ChangeEvent<HTMLInputElement>) => {
......@@ -22,7 +22,7 @@ const SearchBar = () => {
return (
<>
<SearchBarDesktop onChange={ handleChange } onSubmit={ handleSubmit }/>
<SearchBarMobile onChange={ handleChange } onSubmit={ handleSubmit }/>
<SearchBarMobile onChange={ handleChange } onSubmit={ handleSubmit } withShadow={ withShadow }/>
</>
);
};
......
......@@ -4,29 +4,27 @@ import React from 'react';
import type { ChangeEvent, FormEvent } from 'react';
import searchIcon from 'icons/search.svg';
import useScrollDirection from 'lib/hooks/useScrollDirection';
import ScrollDirectionContext from 'ui/ScrollDirectionContext';
const TOP = 55;
interface Props {
onChange: (event: ChangeEvent<HTMLInputElement>) => void;
onSubmit: (event: FormEvent<HTMLFormElement>) => void;
withShadow?: boolean;
}
const SearchBarMobile = ({ onChange, onSubmit }: Props) => {
const scrollDirection = useScrollDirection();
const isVisible = !scrollDirection || scrollDirection === 'up';
const SearchBarMobile = ({ onChange, onSubmit, withShadow }: Props) => {
const [ isSticky, setIsSticky ] = React.useState(false);
const handleScroll = React.useCallback(() => {
if (window.pageYOffset === 0 || !isVisible) {
setIsSticky(false);
} else {
if (window.pageYOffset !== 0) {
setIsSticky(true);
} else {
setIsSticky(false);
}
}, [ isVisible ]);
}, []);
React.useEffect(() => {
const throttledHandleScroll = throttle(handleScroll, 300);
......@@ -45,37 +43,41 @@ const SearchBarMobile = ({ onChange, onSubmit }: Props) => {
const bgColor = useColorModeValue('white', 'black');
return (
<chakra.form
noValidate
onSubmit={ onSubmit }
paddingX={ 4 }
paddingTop={ 1 }
paddingBottom={ 2 }
position="fixed"
top={ `${ TOP }px` }
left="0"
zIndex="sticky1"
bgColor={ bgColor }
transform={ isVisible ? 'translateY(0)' : 'translateY(-112px)' }
transitionProperty="transform,box-shadow"
transitionDuration="slow"
display={{ base: 'block', lg: 'none' }}
w="100%"
boxShadow={ isVisible && isSticky ? 'md' : 'none' }
>
<InputGroup size="sm">
<InputLeftElement >
<Icon as={ searchIcon } boxSize={ 4 } color={ searchIconColor }/>
</InputLeftElement>
<Input
paddingInlineStart="38px"
placeholder="Search by addresses / ... "
ml="1px"
onChange={ onChange }
borderColor={ inputBorderColor }
/>
</InputGroup>
</chakra.form>
<ScrollDirectionContext.Consumer>
{ (scrollDirection) => (
<chakra.form
noValidate
onSubmit={ onSubmit }
paddingX={ 4 }
paddingTop={ 1 }
paddingBottom={ 2 }
position="fixed"
top={ `${ TOP }px` }
left="0"
zIndex="sticky1"
bgColor={ bgColor }
transform={ scrollDirection !== 'down' ? 'translateY(0)' : 'translateY(-100%)' }
transitionProperty="transform,box-shadow"
transitionDuration="slow"
display={{ base: 'block', lg: 'none' }}
w="100%"
boxShadow={ withShadow && scrollDirection !== 'down' && isSticky ? 'md' : 'none' }
>
<InputGroup size="sm">
<InputLeftElement >
<Icon as={ searchIcon } boxSize={ 4 } color={ searchIconColor }/>
</InputLeftElement>
<Input
paddingInlineStart="38px"
placeholder="Search by addresses / ... "
ml="1px"
onChange={ onChange }
borderColor={ inputBorderColor }
/>
</InputGroup>
</chakra.form>
) }
</ScrollDirectionContext.Consumer>
);
};
......
import { Table, Thead, Tbody, Tr, Th, TableContainer, Link, Icon } from '@chakra-ui/react';
import { Table, Thead, Tbody, Tr, Th, Link, Icon } from '@chakra-ui/react';
import React from 'react';
import type { InternalTransaction } from 'types/api/internalTransaction';
......@@ -18,35 +18,33 @@ const TxInternalsTable = ({ data, sort, onSortToggle }: Props) => {
const sortIconTransform = sort?.includes('asc') ? 'rotate(-90deg)' : 'rotate(90deg)';
return (
<TableContainer width="100%" mt={ 6 }>
<Table variant="simple" size="sm">
<Thead>
<Tr>
<Th width="28%">Type</Th>
<Th width="20%">From</Th>
<Th width="24px" px={ 0 }/>
<Th width="20%">To</Th>
<Th width="16%" isNumeric>
<Link display="flex" alignItems="center" justifyContent="flex-end" onClick={ onSortToggle('value') } columnGap={ 1 }>
{ sort?.includes('value') && <Icon as={ arrowIcon } boxSize={ 4 } transform={ sortIconTransform }/> }
<Table variant="simple" size="sm" mt={ 6 }>
<Thead>
<Tr>
<Th width="28%">Type</Th>
<Th width="20%">From</Th>
<Th width="24px" px={ 0 }/>
<Th width="20%">To</Th>
<Th width="16%" isNumeric>
<Link display="flex" alignItems="center" justifyContent="flex-end" onClick={ onSortToggle('value') } columnGap={ 1 }>
{ sort?.includes('value') && <Icon as={ arrowIcon } boxSize={ 4 } transform={ sortIconTransform }/> }
Value { appConfig.network.currency.symbol }
</Link>
</Th>
<Th width="16%" isNumeric>
<Link display="flex" alignItems="center" justifyContent="flex-end" onClick={ onSortToggle('gas-limit') } columnGap={ 1 }>
{ sort?.includes('gas-limit') && <Icon as={ arrowIcon } boxSize={ 4 } transform={ sortIconTransform }/> }
</Link>
</Th>
<Th width="16%" isNumeric>
<Link display="flex" alignItems="center" justifyContent="flex-end" onClick={ onSortToggle('gas-limit') } columnGap={ 1 }>
{ sort?.includes('gas-limit') && <Icon as={ arrowIcon } boxSize={ 4 } transform={ sortIconTransform }/> }
Gas limit { appConfig.network.currency.symbol }
</Link>
</Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item) => (
<TxInternalsTableItem key={ item.transaction_hash } { ...item }/>
)) }
</Tbody>
</Table>
</TableContainer>
</Link>
</Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item) => (
<TxInternalsTableItem key={ item.transaction_hash } { ...item }/>
)) }
</Tbody>
</Table>
);
};
......
......@@ -4,7 +4,6 @@ import {
Tbody,
Tr,
Th,
TableContainer,
} from '@chakra-ui/react';
import capitalize from 'lodash/capitalize';
import React from 'react';
......@@ -16,23 +15,21 @@ import TxStateTableItem from 'ui/tx/state/TxStateTableItem';
const TxStateTable = () => {
return (
<TableContainer width="100%" mt={ 6 }>
<Table variant="simple" minWidth="950px" size="sm" w="auto">
<Thead>
<Tr>
<Th width="92px">Storage</Th>
<Th width="146px">Address</Th>
<Th width="120px">{ capitalize(getNetworkValidatorTitle()) }</Th>
<Th width="33%" isNumeric>{ `After ${ appConfig.network.currency.symbol }` }</Th>
<Th width="33%" isNumeric>{ `Before ${ appConfig.network.currency.symbol }` }</Th>
<Th width="33%" isNumeric>{ `State difference ${ appConfig.network.currency.symbol }` }</Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item, index) => <TxStateTableItem txStateItem={ item } key={ index }/>) }
</Tbody>
</Table>
</TableContainer>
<Table variant="simple" minWidth="950px" size="sm" w="auto" mt={ 6 }>
<Thead>
<Tr>
<Th width="92px">Storage</Th>
<Th width="146px">Address</Th>
<Th width="120px">{ capitalize(getNetworkValidatorTitle()) }</Th>
<Th width="33%" isNumeric>{ `After ${ appConfig.network.currency.symbol }` }</Th>
<Th width="33%" isNumeric>{ `Before ${ appConfig.network.currency.symbol }` }</Th>
<Th width="33%" isNumeric>{ `State difference ${ appConfig.network.currency.symbol }` }</Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item, index) => <TxStateTableItem txStateItem={ item } key={ index }/>) }
</Tbody>
</Table>
);
};
......
......@@ -6,15 +6,11 @@ import type { QueryKeys } from 'types/client/queries';
import type { Sort } from 'types/client/txs-sort';
import * as cookies from 'lib/cookies';
import useIsMobile from 'lib/hooks/useIsMobile';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
// import FilterInput from 'ui/shared/FilterInput';
import Pagination from 'ui/shared/Pagination';
import TxsHeader from './TxsHeader';
import TxsSkeletonDesktop from './TxsSkeletonDesktop';
import TxsSkeletonMobile from './TxsSkeletonMobile';
import TxsSorting from './TxsSorting';
import TxsWithSort from './TxsWithSort';
import useQueryWithPages from './useQueryWithPages';
......@@ -91,7 +87,7 @@ const TxsContent = ({
const paginationProps = {
...pagination,
hasNextPage: data?.next_page_params !== undefined && Object.keys(data?.next_page_params).length > 0,
hasNextPage: data?.next_page_params !== undefined && data?.next_page_params !== null && Object.keys(data?.next_page_params).length > 0,
};
return (
......
......@@ -6,7 +6,7 @@ import type { Sort } from 'types/client/txs-sort';
import useIsMobile from 'lib/hooks/useIsMobile';
// import FilterInput from 'ui/shared/FilterInput';
import useScrollDirection from 'lib/hooks/useScrollDirection';
import ScrollDirectionContext from 'ui/ScrollDirectionContext';
import Pagination from 'ui/shared/Pagination';
import type { Props as PaginationProps } from 'ui/shared/Pagination';
import SortButton from 'ui/shared/SortButton';
......@@ -22,7 +22,6 @@ const TOP_UP = 106;
const TOP_DOWN = 0;
const TxsHeader = ({ sorting, paginationProps }: Props) => {
const scrollDirection = useScrollDirection();
const [ isSticky, setIsSticky ] = React.useState(false);
const ref = React.useRef<HTMLDivElement>(null);
......@@ -30,14 +29,13 @@ const TxsHeader = ({ sorting, paginationProps }: Props) => {
const handleScroll = useCallback(() => {
if (
Number(ref.current?.getBoundingClientRect().y) <= TOP_DOWN ||
(scrollDirection === 'up' && Number(ref.current?.getBoundingClientRect().y) <= TOP_UP)
Number(ref.current?.getBoundingClientRect().y) < TOP_UP + 5
) {
setIsSticky(true);
} else {
setIsSticky(false);
}
}, [ scrollDirection ]);
}, [ ]);
React.useEffect(() => {
const throttledHandleScroll = throttle(handleScroll, 300);
......@@ -47,51 +45,59 @@ const TxsHeader = ({ sorting, paginationProps }: Props) => {
return () => {
window.removeEventListener('scroll', throttledHandleScroll);
};
}, [ handleScroll ]);
// replicate componentDidMount
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ ]);
const bgColor = useColorModeValue('white', 'black');
return (
<Flex
backgroundColor={ useColorModeValue('white', 'black') }
mt={ -6 }
pt={ 6 }
pb={ 6 }
mx={{ base: -4, lg: 0 }}
px={{ base: 4, lg: 0 }}
justifyContent="space-between"
width={{ base: '100vw', lg: 'unset' }}
position="sticky"
top={{ base: scrollDirection === 'down' ? `${ TOP_DOWN }px` : `${ TOP_UP }px`, lg: 0 }}
transitionProperty="top"
transitionDuration="slow"
zIndex={{ base: 'sticky2', lg: 'docked' }}
boxShadow={{ base: isSticky ? 'md' : 'none', lg: 'none' }}
ref={ ref }
>
<HStack>
{ /* api is not implemented */ }
{ /* <TxsFilters
<ScrollDirectionContext.Consumer>
{ (scrollDirection) => (
<Flex
backgroundColor={ bgColor }
mt={ -6 }
pt={ 6 }
pb={ 6 }
mx={{ base: -4, lg: 0 }}
px={{ base: 4, lg: 0 }}
justifyContent="space-between"
width={{ base: '100vw', lg: 'unset' }}
position="sticky"
top={{ base: scrollDirection === 'down' ? `${ TOP_DOWN }px` : `${ TOP_UP }px`, lg: 0 }}
transitionProperty="top,box-shadow"
transitionDuration="slow"
zIndex={{ base: 'sticky2', lg: 'docked' }}
boxShadow={{ base: isSticky ? 'md' : 'none', lg: 'none' }}
ref={ ref }
>
<HStack>
{ /* api is not implemented */ }
{ /* <TxsFilters
filters={ filters }
onFiltersChange={ setFilters }
appliedFiltersNum={ 0 }
/> */ }
{ isMobile && (
<SortButton
// eslint-disable-next-line react/jsx-no-bind
handleSort={ () => {} }
isSortActive={ Boolean(sorting) }
/>
) }
{ /* api is not implemented */ }
{ /* <FilterInput
{ isMobile && (
<SortButton
// eslint-disable-next-line react/jsx-no-bind
handleSort={ () => {} }
isSortActive={ Boolean(sorting) }
/>
) }
{ /* api is not implemented */ }
{ /* <FilterInput
// eslint-disable-next-line react/jsx-no-bind
onChange={ () => {} }
maxW="360px"
size="xs"
placeholder="Search by addresses, hash, method..."
/> */ }
</HStack>
<Pagination { ...paginationProps }/>
</Flex>
</HStack>
<Pagination { ...paginationProps }/>
</Flex>
) }
</ScrollDirectionContext.Consumer>
);
};
......
import { Link, Table, Thead, Tbody, Tr, Th, TableContainer, Icon } from '@chakra-ui/react';
import { Link, Table, Tbody, Tr, Th, Icon } from '@chakra-ui/react';
import React from 'react';
import type { Transaction } from 'types/api/transaction';
......@@ -6,6 +6,7 @@ import type { Sort } from 'types/client/txs-sort';
import appConfig from 'configs/app/config';
import rightArrowIcon from 'icons/arrows/east.svg';
import TheadSticky from 'ui/shared/TheadSticky';
import TxsTableItem from './TxsTableItem';
......@@ -17,44 +18,42 @@ type Props = {
const TxsTable = ({ txs, sort, sorting }: Props) => {
return (
<TableContainer width="100%">
<Table variant="simple" minWidth="810px" size="xs">
<Thead>
<Tr>
<Th width="54px"></Th>
<Th width="20%">Type</Th>
<Th width="18%">Txn hash</Th>
<Th width="15%">Method</Th>
<Th width="11%">Block</Th>
<Th width={{ xl: '128px', base: '66px' }}>From</Th>
<Th width={{ xl: '36px', base: '0' }}></Th>
<Th width={{ xl: '128px', base: '66px' }}>To</Th>
<Th width="18%" isNumeric>
<Link onClick={ sort('val') } display="flex" justifyContent="end">
{ sorting === 'val-asc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(-90deg)"/> }
{ sorting === 'val-desc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(90deg)"/> }
{ `Value ${ appConfig.network.currency.symbol }` }
</Link>
</Th>
<Th width="18%" isNumeric pr={ 5 }>
<Link onClick={ sort('fee') } display="flex" justifyContent="end">
{ sorting === 'fee-asc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(-90deg)"/> }
{ sorting === 'fee-desc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(90deg)"/> }
{ `Fee ${ appConfig.network.currency.symbol }` }
</Link>
</Th>
</Tr>
</Thead>
<Tbody>
{ txs.map((item) => (
<TxsTableItem
key={ item.hash }
tx={ item }
/>
)) }
</Tbody>
</Table>
</TableContainer>
<Table variant="simple" minWidth="810px" size="xs">
<TheadSticky top={ 80 }>
<Tr>
<Th width="54px"></Th>
<Th width="20%">Type</Th>
<Th width="18%">Txn hash</Th>
<Th width="15%">Method</Th>
<Th width="11%">Block</Th>
<Th width={{ xl: '128px', base: '66px' }}>From</Th>
<Th width={{ xl: '36px', base: '0' }}></Th>
<Th width={{ xl: '128px', base: '66px' }}>To</Th>
<Th width="18%" isNumeric>
<Link onClick={ sort('val') } display="flex" justifyContent="end">
{ sorting === 'val-asc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(-90deg)"/> }
{ sorting === 'val-desc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(90deg)"/> }
{ `Value ${ appConfig.network.currency.symbol }` }
</Link>
</Th>
<Th width="18%" isNumeric pr={ 5 }>
<Link onClick={ sort('fee') } display="flex" justifyContent="end">
{ sorting === 'fee-asc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(-90deg)"/> }
{ sorting === 'fee-desc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(90deg)"/> }
{ `Fee ${ appConfig.network.currency.symbol }` }
</Link>
</Th>
</Tr>
</TheadSticky>
<Tbody>
{ txs.map((item) => (
<TxsTableItem
key={ item.hash }
tx={ item }
/>
)) }
</Tbody>
</Table>
);
};
......
......@@ -4,7 +4,6 @@ import {
Tbody,
Tr,
Th,
TableContainer,
} from '@chakra-ui/react';
import React from 'react';
......@@ -20,28 +19,26 @@ interface Props {
const WatchlistTable = ({ data, onDeleteClick, onEditClick }: Props) => {
return (
<TableContainer width="100%">
<Table variant="simple" minWidth="600px">
<Thead>
<Tr>
<Th width="70%">Address</Th>
<Th width="30%">Private tag</Th>
<Th width="160px">Email notification</Th>
<Th width="108px"></Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item) => (
<WatchlistTableItem
item={ item }
key={ item.address_hash }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
/>
)) }
</Tbody>
</Table>
</TableContainer>
<Table variant="simple" minWidth="600px">
<Thead>
<Tr>
<Th width="70%">Address</Th>
<Th width="30%">Private tag</Th>
<Th width="160px">Email notification</Th>
<Th width="108px"></Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item) => (
<WatchlistTableItem
item={ item }
key={ item.address_hash }
onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick }
/>
)) }
</Tbody>
</Table>
);
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment