Skip to content

Commit

Permalink
feat: clear filter
Browse files Browse the repository at this point in the history
  • Loading branch information
danielsimao committed Jan 24, 2025
1 parent 99b01fb commit d18cae0
Show file tree
Hide file tree
Showing 4 changed files with 254 additions and 224 deletions.
171 changes: 96 additions & 75 deletions apps/evm/src/components/ProfileActivity/ProfileActivity.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,72 @@
import { Flex, P, Skeleton } from '@gobob/ui';
import { Button, Flex, P, Skeleton } from '@gobob/ui';
import { Trans } from '@lingui/macro';
import { useStore } from '@tanstack/react-store';
import { watchAccount } from '@wagmi/core';
import { useEffect, useMemo, useRef } from 'react';
import { useConfig } from 'wagmi';

import { StyledTransactionList } from './ProfileActivity.style';
import {
ProfileActivityFilters,
ProfileActivityFiltersData,
ProfileActivityStatusFilterOption,
ProfileActivityTypeFilterOption
} from './ProfileActivityFilters';
import { ProfileActivityFilters, ProfileActivityFiltersData } from './ProfileActivityFilters';
import { TransactionItem } from './TransactionItem';

import { useGetBridgeTransactions, useGetGatewayTransactions } from '@/hooks';
import { store } from '@/lib/store';
import { BridgeTransactionStatus, GatewayTransactionType, TransactionType } from '@/types';
import { SharedStoreProfileTxStatus, SharedStoreProfileTxType, store } from '@/lib/store';
import {
BridgeTransaction,
BridgeTransactionStatus,
GatewayTransaction,
GatewayTransactionType,
TransactionType
} from '@/types';

const filterByType = (
bridgeData: BridgeTransaction[],
gatewayData: GatewayTransaction[],
type?: SharedStoreProfileTxType
) => {
switch (type) {
case SharedStoreProfileTxType.BTC_BRIDGE:
return gatewayData?.filter((item) => item.subType === GatewayTransactionType.BRIDGE) || [];
case SharedStoreProfileTxType.STRATEGIES:
return gatewayData?.filter((item) => item.subType === GatewayTransactionType.STRATEGY) || [];
case SharedStoreProfileTxType.NATIVE_BRIDGE:
return bridgeData;
default:
case SharedStoreProfileTxType.ALL_TRANSACTIONS:
return [...bridgeData, ...gatewayData];
}
};

const filterByStatus = (data: Array<BridgeTransaction | GatewayTransaction>, status?: SharedStoreProfileTxStatus) => {
switch (status) {
case SharedStoreProfileTxStatus.PENDING:
return data.filter((item) =>
item.type === TransactionType.Bridge
? item.status !== BridgeTransactionStatus.RELAYED
: item.status !== 'l2-confirmation'
);
case SharedStoreProfileTxStatus.COMPLETE:
return data.filter((item) =>
item.type === TransactionType.Bridge
? item.status === BridgeTransactionStatus.RELAYED
: item.status === 'l2-confirmation'
);
case SharedStoreProfileTxStatus.FAILED:
return data.filter((item) =>
item.type === TransactionType.Bridge ? item.status === BridgeTransactionStatus.FAILED_L1_TO_L2_MESSAGE : false
);
case SharedStoreProfileTxStatus.NEEDED_ACTION:
return data.filter((item) =>
item.type === TransactionType.Bridge
? item.status === BridgeTransactionStatus.READY_TO_PROVE ||
item.status === BridgeTransactionStatus.READY_FOR_RELAY
: false
);
default:
case SharedStoreProfileTxStatus.ANY_STATUS:
return data;
}
};

const ProfileActivity = (): JSX.Element => {
const { filters } = useStore(store, (state) => state.shared.profile.transactions);
Expand Down Expand Up @@ -57,76 +107,38 @@ const ProfileActivity = (): JSX.Element => {
}
}, [isInitialLoading, isLoading]);

const dataByType = useMemo(() => {
switch (filters.type) {
case ProfileActivityTypeFilterOption.BTC_BRIDGE:
return gateway.data?.filter((item) => item.subType === GatewayTransactionType.BRIDGE) || [];
case ProfileActivityTypeFilterOption.STRATEGIES:
return gateway.data?.filter((item) => item.subType === GatewayTransactionType.STRATEGY) || [];
case ProfileActivityTypeFilterOption.NATIVE_BRIDGE:
return bridge.data;
default:
case ProfileActivityTypeFilterOption.ALL_TRANSACTIONS:
return [...bridge.data, ...(gateway?.data || [])];
}
}, [bridge.data, gateway.data, filters.type]);

const dataByStatus = useMemo(() => {
switch (filters.status) {
case ProfileActivityStatusFilterOption.PENDING:
return dataByType.filter((item) =>
item.type === TransactionType.Bridge
? item.status !== BridgeTransactionStatus.RELAYED
: item.status !== 'l2-confirmation'
);
case ProfileActivityStatusFilterOption.COMPLETE:
return dataByType.filter((item) =>
item.type === TransactionType.Bridge
? item.status === BridgeTransactionStatus.RELAYED
: item.status === 'l2-confirmation'
);
case ProfileActivityStatusFilterOption.FAILED:
return dataByType.filter((item) =>
item.type === TransactionType.Bridge ? item.status === BridgeTransactionStatus.FAILED_L1_TO_L2_MESSAGE : false
);
case ProfileActivityStatusFilterOption.NEEDED_ACTION:
return dataByType.filter((item) =>
item.type === TransactionType.Bridge
? item.status === BridgeTransactionStatus.READY_TO_PROVE ||
item.status === BridgeTransactionStatus.READY_FOR_RELAY
: false
);

default:
case ProfileActivityStatusFilterOption.ANY_STATUS:
return dataByType;
}
}, [dataByType, filters.status]);
const handleFilterSelectionChange = (value: ProfileActivityFiltersData) =>
store.setState((state) => ({
...state,
shared: {
...state.shared,
profile: {
...state.shared.profile,
transactions: {
...state.shared.profile.transactions,
filters: value
}
}
}
}));

const isFiltering = !!(filters.status || filters.type);

const sortedData = useMemo(() => {
return dataByStatus?.sort((a, b) => b.date.getTime() - a.date.getTime());
}, [dataByStatus]);
const data = useMemo(() => {
const filteredByType = filterByType(bridge.data, gateway.data || [], filters.type);

const filteredByStatus = filterByStatus(filteredByType, filters.status);

return filteredByStatus?.sort((a, b) => b.date.getTime() - a.date.getTime());
}, [bridge.data, filters.status, filters.type, gateway.data]);

return (
<Flex direction='column' marginTop='md'>
<Flex wrap gap='s' justifyContent='flex-end'>
<ProfileActivityFilters
isFiltering={isFiltering}
value={filters as ProfileActivityFiltersData}
onSelectionChange={(value) =>
store.setState((state) => ({
...state,
shared: {
...state.shared,
profile: {
...state.shared.profile,
transactions: {
...state.shared.profile.transactions,
filters: value
}
}
}
}))
}
onSelectionChange={handleFilterSelectionChange}
/>
</Flex>
<StyledTransactionList direction='column' elementType='ul' flex={1} marginTop='md'>
Expand All @@ -147,8 +159,8 @@ const ProfileActivity = (): JSX.Element => {
))
) : (
<>
{sortedData?.length ? (
sortedData.map((data, key) => (
{data?.length ? (
data.map((data, key) => (
<TransactionItem
key={key}
data={data}
Expand All @@ -157,10 +169,19 @@ const ProfileActivity = (): JSX.Element => {
/>
))
) : (
<Flex alignItems='center' gap='md' justifyContent='center' marginY='8xl'>
<Flex alignItems='center' direction='column' gap='xl' justifyContent='center' marginY='8xl'>
<P align='center' size='s'>
<Trans>No operations found</Trans>
</P>
{isFiltering && (
<Button
color='light'
size='s'
onPress={() => handleFilterSelectionChange({ status: undefined, type: undefined })}
>
<Trans>Clear Filters</Trans>
</Button>
)}
</Flex>
)}
</>
Expand Down
85 changes: 42 additions & 43 deletions apps/evm/src/components/ProfileActivity/ProfileActivityFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,54 +14,45 @@ import {
import { Trans } from '@lingui/macro';
import { useEffect, useId, useState } from 'react';

enum ProfileActivityStatusFilterOption {
ANY_STATUS = 'default',
PENDING = 'pending',
NEEDED_ACTION = 'needed-action',
COMPLETE = 'complete',
FAILED = 'failed'
}

enum ProfileActivityTypeFilterOption {
ALL_TRANSACTIONS = 'default',
NATIVE_BRIDGE = 'native-bridge',
BTC_BRIDGE = 'btc-bridge',
STRATEGIES = 'strategies'
}
import { SharedStoreProfileTxStatus, SharedStoreProfileTxType } from '@/lib/store';

const statusFilterOptions = [
{ children: <Trans>Any Status</Trans>, key: ProfileActivityStatusFilterOption.ANY_STATUS },
{ children: <Trans>Pending</Trans>, key: ProfileActivityStatusFilterOption.PENDING },
{ children: <Trans>Needed Action</Trans>, key: ProfileActivityStatusFilterOption.NEEDED_ACTION },
{ children: <Trans>Complete</Trans>, key: ProfileActivityStatusFilterOption.COMPLETE },
{ children: <Trans>Failed</Trans>, key: ProfileActivityStatusFilterOption.FAILED }
{ children: <Trans>Any Status</Trans>, key: SharedStoreProfileTxStatus.ANY_STATUS },
{ children: <Trans>Pending</Trans>, key: SharedStoreProfileTxStatus.PENDING },
{ children: <Trans>Needed Action</Trans>, key: SharedStoreProfileTxStatus.NEEDED_ACTION },
{ children: <Trans>Complete</Trans>, key: SharedStoreProfileTxStatus.COMPLETE },
{ children: <Trans>Failed</Trans>, key: SharedStoreProfileTxStatus.FAILED }
];

const typeFilterOptions = [
{ children: <Trans>Any Transaction</Trans>, key: ProfileActivityTypeFilterOption.ALL_TRANSACTIONS },
{ children: <Trans>Native Bridge</Trans>, key: ProfileActivityTypeFilterOption.NATIVE_BRIDGE },
{ children: <Trans>BTC Bridge</Trans>, key: ProfileActivityTypeFilterOption.BTC_BRIDGE },
{ children: <Trans>Staking</Trans>, key: ProfileActivityTypeFilterOption.STRATEGIES }
{ children: <Trans>Any Transaction</Trans>, key: SharedStoreProfileTxType.ALL_TRANSACTIONS },
{ children: <Trans>Native Bridge</Trans>, key: SharedStoreProfileTxType.NATIVE_BRIDGE },
{ children: <Trans>BTC Bridge</Trans>, key: SharedStoreProfileTxType.BTC_BRIDGE },
{ children: <Trans>Staking</Trans>, key: SharedStoreProfileTxType.STRATEGIES }
];

type ProfileActivityFiltersData = { type: ProfileActivityTypeFilterOption; status: ProfileActivityStatusFilterOption };
type ProfileActivityFiltersData = { type?: SharedStoreProfileTxType; status?: SharedStoreProfileTxStatus };

type ProfileActivityFiltersProps = {
isFiltering: boolean;
value: ProfileActivityFiltersData;
onSelectionChange: (filters: ProfileActivityFiltersData) => void;
};

const ProfileActivityFilters = ({ value, onSelectionChange }: ProfileActivityFiltersProps): JSX.Element => {
const ProfileActivityFilters = ({
isFiltering,
value,
onSelectionChange
}: ProfileActivityFiltersProps): JSX.Element => {
const statusLabelId = useId();
const typeLabelId = useId();

const [state, setState] = useState<ProfileActivityFiltersData>({
status: value.status || ProfileActivityStatusFilterOption.ANY_STATUS,
type: value.type || ProfileActivityTypeFilterOption.ALL_TRANSACTIONS
});
const [state, setState] = useState<ProfileActivityFiltersData>(value);
const [isOpen, setOpen] = useState(false);

useEffect(() => {}, [isOpen]);
useEffect(() => {
setState(value);
}, [value]);

const handleApply = () => {
onSelectionChange(state);
Expand All @@ -78,8 +69,8 @@ const ProfileActivityFilters = ({ value, onSelectionChange }: ProfileActivityFil

const handleClear = () => {
const clearState = {
status: ProfileActivityStatusFilterOption.ANY_STATUS,
type: ProfileActivityTypeFilterOption.ALL_TRANSACTIONS
status: undefined,
type: undefined
};

setState(clearState);
Expand All @@ -88,15 +79,11 @@ const ProfileActivityFilters = ({ value, onSelectionChange }: ProfileActivityFil
setOpen(false);
};

const isFiltering =
(value.status && value.status !== ProfileActivityStatusFilterOption.ANY_STATUS) ||
(value.type && value.type !== ProfileActivityTypeFilterOption.ALL_TRANSACTIONS);

const statusLabel = statusFilterOptions.find(
(item) => item.key === (value.status || ProfileActivityStatusFilterOption.ANY_STATUS)
(item) => item.key === (value.status || SharedStoreProfileTxStatus.ANY_STATUS)
)?.children;
const typeLabel = typeFilterOptions.find(
(item) => item.key === (value.type || ProfileActivityTypeFilterOption.ALL_TRANSACTIONS)
(item) => item.key === (value.type || SharedStoreProfileTxType.ALL_TRANSACTIONS)
)?.children;

return (
Expand Down Expand Up @@ -138,12 +125,18 @@ const ProfileActivityFilters = ({ value, onSelectionChange }: ProfileActivityFil
</Span>
<List
aria-labelledby={statusLabelId}
selectedKeys={state.status ? [state.status] : undefined}
selectedKeys={state.status ? [state.status] : [SharedStoreProfileTxStatus.ANY_STATUS]}
selectionMode='single'
onSelectionChange={(key) => {
const [selectedKey] = [...key];

setState((s) => ({ ...s, status: selectedKey as ProfileActivityStatusFilterOption }));
setState((s) => ({
...s,
status:
selectedKey === SharedStoreProfileTxStatus.ANY_STATUS
? undefined
: (selectedKey as SharedStoreProfileTxStatus)
}));
}}
>
{statusFilterOptions.map((option) => (
Expand All @@ -159,12 +152,18 @@ const ProfileActivityFilters = ({ value, onSelectionChange }: ProfileActivityFil
</Span>
<List
aria-labelledby={typeLabelId}
selectedKeys={state.type ? [state.type] : undefined}
selectedKeys={state.type ? [state.type] : [SharedStoreProfileTxType.ALL_TRANSACTIONS]}
selectionMode='single'
onSelectionChange={(key) => {
const [selectedKey] = [...key];

setState((s) => ({ ...s, type: selectedKey as ProfileActivityTypeFilterOption }));
setState((s) => ({
...s,
type:
selectedKey === SharedStoreProfileTxType.ALL_TRANSACTIONS
? undefined
: (selectedKey as SharedStoreProfileTxType)
}));
}}
>
{typeFilterOptions.map((option) => (
Expand All @@ -189,5 +188,5 @@ const ProfileActivityFilters = ({ value, onSelectionChange }: ProfileActivityFil
);
};

export { ProfileActivityFilters, ProfileActivityStatusFilterOption, ProfileActivityTypeFilterOption };
export { ProfileActivityFilters };
export type { ProfileActivityFiltersData };
Loading

0 comments on commit d18cae0

Please sign in to comment.