Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions icons/list_view.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions lib/cookies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export enum NAMES {
UUID = 'uuid',
SHOW_SCAM_TOKENS = 'show_scam_tokens',
APP_PROFILE = 'app_profile',
TABLE_VIEW_ON_MOBILE = 'table_view_on_mobile',
}

/**
Expand Down
1 change: 1 addition & 0 deletions lib/growthbook/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { STORAGE_KEY, STORAGE_LIMIT } from './consts';

export interface GrowthBookFeatures {
test_value: string;
txns_view_exp: 'table_view' | 'list_view';
}

export const initGrowthBook = (uuid: string) => {
Expand Down
47 changes: 47 additions & 0 deletions lib/hooks/useTableViewValue.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';

import * as cookies from 'lib/cookies';
import useFeatureValue from 'lib/growthbook/useFeatureValue';
import * as mixpanel from 'lib/mixpanel';

export default function useTableViewValue() {
const cookieValue = cookies.get(cookies.NAMES.TABLE_VIEW_ON_MOBILE);
const [ value, setValue ] = React.useState<boolean | undefined>(cookieValue ? cookieValue === 'true' : undefined);
const { value: featureFlag, isLoading: isFeatureLoading } = useFeatureValue('txns_view_exp', 'list_view');

const onToggle = React.useCallback(() => {
setValue((prev) => {
const nextValue = !prev;
cookies.set(cookies.NAMES.TABLE_VIEW_ON_MOBILE, nextValue ? 'true' : 'false');
mixpanel.logEvent(mixpanel.EventTypes.PAGE_WIDGET, {
Type: 'Txn view switch',
Info: nextValue ? 'Table view' : 'List view',
Source: 'Address page',
});
return nextValue;
});
}, []);

React.useEffect(() => {
if (!isFeatureLoading) {
setValue((prev) => {
if (prev === undefined) {
return featureFlag === 'table_view';
}
return prev;
});
}
}, [ featureFlag, isFeatureLoading ]);

return React.useMemo(() => {
if (value !== undefined) {
return {
value,
isLoading: false,
onToggle,
};
}

return { value: featureFlag === 'table_view', isLoading: isFeatureLoading, onToggle };
}, [ featureFlag, isFeatureLoading, onToggle, value ]);
}
4 changes: 4 additions & 0 deletions lib/mixpanel/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ Type extends EventTypes.PAGE_WIDGET ? (
Type: 'Chain switch';
Info: string;
Source: 'Revoke essential dapp';
} | {
Type: 'Txn view switch';
Info: 'Table view' | 'List view';
Source: 'Address page';
}
) :
Type extends EventTypes.TX_INTERPRETATION_INTERACTION ? {
Expand Down
1 change: 1 addition & 0 deletions public/icons/name.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
| "lightning"
| "link_external"
| "link"
| "list_view"
| "lock"
| "merits_colored"
| "merits_with_dot"
Expand Down
18 changes: 16 additions & 2 deletions ui/address/AddressTxs.pw.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ test.describe('base view', () => {
});
});

test.describe('base view', () => {
test.describe('mobile', () => {
test.use({ viewport: pwConfig.viewport.mobile });

test('mobile', async({ render, mockApiResponse }) => {
test.beforeEach(async({ mockApiResponse }) => {
await mockApiResponse(
'general:address_txs',
{
Expand All @@ -73,6 +73,20 @@ test.describe('base view', () => {
},
{ pathParams: { hash: CURRENT_ADDRESS } },
);
});

test('base view', async({ render }) => {
const component = await render(
<Box pt={{ base: '134px', lg: 6 }}>
<AddressTxs/>
</Box>,
{ hooksConfig },
);
await expect(component).toHaveScreenshot();
});

test('table view', async({ render, mockFeatures }) => {
await mockFeatures([ [ 'txns_view_exp', 'table_view' ] ]);
const component = await render(
<Box pt={{ base: '134px', lg: 6 }}>
<AddressTxs/>
Expand Down
1 change: 1 addition & 0 deletions ui/address/AddressTxs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ const AddressTxs = ({ shouldRender = true, isQueryEnabled = true }: Props) => {
top={ ACTION_BAR_HEIGHT_DESKTOP }
sorting={ sort }
setSort={ setSort }
showTableViewButton
/>
</>
);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions ui/shared/TableViewToggleButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';

import { IconButton } from 'toolkit/chakra/icon-button';
import IconSvg from 'ui/shared/IconSvg';

interface Props {
value: boolean;
onClick: () => void;
loading?: boolean;
}

const TableViewToggleButton = ({ value, onClick, loading }: Props) => {
return (
<IconButton
size="md"
variant="dropdown"
onClick={ onClick }
selected={ !value }
loadingSkeleton={ loading }
>
<IconSvg name="list_view"/>
</IconButton>
);
};

export default React.memo(TableViewToggleButton);
36 changes: 29 additions & 7 deletions ui/txs/TxsContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import type { Transaction, TransactionsSortingField, TransactionsSortingValue }
import type { PaginationParams } from 'ui/shared/pagination/types';

import useIsMobile from 'lib/hooks/useIsMobile';
import useTableViewValue from 'lib/hooks/useTableViewValue';
import AddressCsvExportLink from 'ui/address/AddressCsvExportLink';
import { ACTION_BAR_HEIGHT_DESKTOP } from 'ui/shared/ActionBar';
import DataListDisplay from 'ui/shared/DataListDisplay';
import getNextSortValue from 'ui/shared/sort/getNextSortValue';
import TableViewToggleButton from 'ui/shared/TableViewToggleButton';

import useDescribeTxs from './noves/useDescribeTxs';
import TxsHeaderMobile from './TxsHeaderMobile';
Expand Down Expand Up @@ -38,6 +40,7 @@ type Props = {
setSorting?: (value: TransactionsSortingValue) => void;
sort: TransactionsSortingValue;
stickyHeader?: boolean;
showTableViewButton?: boolean;
};

const TxsContent = ({
Expand All @@ -55,9 +58,15 @@ const TxsContent = ({
setSorting,
sort,
stickyHeader = true,
showTableViewButton,
}: Props) => {
const isMobile = useIsMobile();

const tableViewFlag = useTableViewValue();

const isTableView = isMobile ? showTableViewButton && !tableViewFlag.isLoading && tableViewFlag.value : true;
const isLoading = isPlaceholderData || tableViewFlag.isLoading;

const onSortToggle = React.useCallback((field: TransactionsSortingField) => {
const value = getNextSortValue<TransactionsSortingField, TransactionsSortingValue>(SORT_SEQUENCE, field)(sort);
setSorting?.(value);
Expand All @@ -67,18 +76,23 @@ const TxsContent = ({

const content = items && items.length > 0 ? (
<>
<Box hideFrom="lg">
<Box display={ isTableView ? 'none' : 'block' }>
<TxsList
showBlockInfo={ showBlockInfo }
socketType={ socketType }
isLoading={ isPlaceholderData }
isLoading={ isLoading }
enableTimeIncrement={ enableTimeIncrement }
currentAddress={ currentAddress }
items={ items }
translationQuery={ translationQuery }
/>
</Box>
<Box hideBelow="lg">
<Box
display={ isTableView ? 'block' : 'none' }
overflowX={ isMobile ? 'scroll' : undefined }
mx={ isMobile ? -3 : 0 }
px={ isMobile ? 3 : 0 }
>
<TxsTable
txs={ items }
sort={ sort }
Expand All @@ -88,14 +102,22 @@ const TxsContent = ({
top={ top || (pagination.isVisible ? ACTION_BAR_HEIGHT_DESKTOP : 0) }
currentAddress={ currentAddress }
enableTimeIncrement={ enableTimeIncrement }
isLoading={ isPlaceholderData }
stickyHeader={ stickyHeader }
isLoading={ isLoading }
stickyHeader={ !isMobile && stickyHeader }
translationQuery={ translationQuery }
/>
</Box>
</>
) : null;

const tableViewButton = isMobile && showTableViewButton ? (
<TableViewToggleButton
value={ tableViewFlag.value }
onClick={ tableViewFlag.onToggle }
loading={ isLoading }
/>
) : null;

const actionBar = isMobile ? (
<TxsHeaderMobile
mt={ -6 }
Expand All @@ -110,8 +132,8 @@ const TxsContent = ({
params={{ type: 'transactions', filterType: 'address', filterValue }}
isLoading={ pagination.isLoading }
/>
) : null
}
) : null }
tableViewButton={ tableViewButton }
/>
) : null;

Expand Down
6 changes: 4 additions & 2 deletions ui/txs/TxsHeaderMobile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,26 @@ type Props = {
showPagination?: boolean;
filterComponent?: React.ReactNode;
linkSlot?: React.ReactNode;
tableViewButton?: React.ReactNode;
};

const collection = createListCollection({
items: SORT_OPTIONS,
});

const TxsHeaderMobile = ({ filterComponent, sorting, setSorting, paginationProps, className, showPagination = true, linkSlot }: Props) => {
const TxsHeaderMobile = ({ filterComponent, sorting, setSorting, paginationProps, className, showPagination = true, linkSlot, tableViewButton }: Props) => {
const handleSortValueChange = React.useCallback(({ value }: { value: Array<string> }) => {
setSorting?.(value[0] as TransactionsSortingValue);
}, [ setSorting ]);

if (!filterComponent && !setSorting && !linkSlot && !showPagination) {
if (!filterComponent && !setSorting && !linkSlot && !showPagination && !tableViewButton) {
return null;
}

return (
<ActionBar className={ className }>
<HStack>
{ tableViewButton }
{ filterComponent }
{ setSorting && (
<Sort
Expand Down
5 changes: 4 additions & 1 deletion ui/txs/TxsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import config from 'configs/app';
import { AddressHighlightProvider } from 'lib/contexts/addressHighlight';
import { useMultichainContext } from 'lib/contexts/multichain';
import useInitialList from 'lib/hooks/useInitialList';
import useIsMobile from 'lib/hooks/useIsMobile';
import useLazyRenderedList from 'lib/hooks/useLazyRenderedList';
import { currencyUnits } from 'lib/units';
import { TableBody, TableColumnHeader, TableColumnHeaderSortable, TableHeader, TableHeaderSticky, TableRoot, TableRow } from 'toolkit/chakra/table';
Expand Down Expand Up @@ -51,6 +52,7 @@ const TxsTable = ({
});
const multichainContext = useMultichainContext();
const chainData = multichainContext?.chain;
const isMobile = useIsMobile();

const feeCurrency = config.UI.views.tx.hiddenFields?.fee_currency || config.chain.hasMultipleGasCurrencies ?
'' :
Expand All @@ -68,7 +70,7 @@ const TxsTable = ({

return (
<AddressHighlightProvider>
<TableRoot minWidth="1000px">
<TableRoot minWidth={{ base: '1200px', lg: '1000px' }}>
<TableHeaderComponent top={ stickyHeader ? top : undefined }>
<TableRow>
<TableColumnHeader width="48px"></TableColumnHeader>
Expand Down Expand Up @@ -142,6 +144,7 @@ const TxsTable = ({
chainData={ chainData }
translationIsLoading={ translationQuery?.isLoading }
translationData={ translationQuery?.data?.find(({ txHash }) => txHash.toLowerCase() === item.hash.toLowerCase()) }
isMobile={ isMobile }
/>
);
}) }
Expand Down
4 changes: 3 additions & 1 deletion ui/txs/TxsTableItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type Props = {
chainData?: ClusterChainConfig;
translationIsLoading?: boolean;
translationData?: NovesDescribeTxsResponse;
isMobile?: boolean;
};

const TxsTableItem = ({
Expand All @@ -46,6 +47,7 @@ const TxsTableItem = ({
chainData,
translationIsLoading,
translationData,
isMobile,
}: Props) => {
const dataTo = tx.to ? tx.to : tx.created_contract;

Expand All @@ -54,7 +56,7 @@ const TxsTableItem = ({
return (
<TableRow key={ tx.hash } animation={ animation }>
<TableCell textAlign="center">
<TxAdditionalInfo tx={ tx } isLoading={ isLoading }/>
<TxAdditionalInfo tx={ tx } isMobile={ isMobile } isLoading={ isLoading }/>
</TableCell>
{ chainData && (
<TableCell>
Expand Down
3 changes: 3 additions & 0 deletions ui/txs/TxsWithAPISorting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type Props = {
top?: number;
sorting: TransactionsSortingValue;
setSort: (value: TransactionsSortingValue) => void;
showTableViewButton?: boolean;
};

const TxsWithAPISorting = ({
Expand All @@ -34,6 +35,7 @@ const TxsWithAPISorting = ({
top,
sorting,
setSort,
showTableViewButton,
}: Props) => {

const handleSortChange = React.useCallback((value: TransactionsSortingValue) => {
Expand All @@ -56,6 +58,7 @@ const TxsWithAPISorting = ({
setSorting={ handleSortChange }
sort={ sorting }
pagination={ query.pagination }
showTableViewButton={ showTableViewButton }
/>
);
};
Expand Down
Loading