mirror of
https://github.com/luxfi/explore.git
synced 2026-10-30 14:46:12 +00:00
211 lines
7.2 KiB
TypeScript
211 lines
7.2 KiB
TypeScript
import { getEnsAddress } from '@wagmi/core';
|
|
import { useRouter } from 'next/router';
|
|
import React, { useMemo, useCallback, useEffect, useState } from 'react';
|
|
import { isAddress } from 'viem';
|
|
import { mainnet } from 'viem/chains';
|
|
import { normalize } from 'viem/ens';
|
|
import { useAccount } from 'wagmi';
|
|
|
|
import config from 'configs/app';
|
|
import essentialDappsChainsConfig from 'configs/essential-dapps-chains';
|
|
import useIsMobile from 'lib/hooks/useIsMobile';
|
|
import * as mixpanel from 'lib/mixpanel';
|
|
import getQueryParamString from 'lib/router/getQueryParamString';
|
|
import { useQueryParams } from 'lib/router/useQueryParams';
|
|
import useWeb3Wallet from 'lib/web3/useWallet';
|
|
import wagmiConfig from 'lib/web3/wagmiConfig';
|
|
import { Button } from '@luxfi/ui/button';
|
|
import { EmptyState } from '@luxfi/ui/empty-state';
|
|
import { Tooltip } from '@luxfi/ui/tooltip';
|
|
|
|
import AddressEntity from './components/AddressEntity';
|
|
import ChainSelect from './components/ChainSelect';
|
|
import Content from './components/Content';
|
|
import SearchInput from './components/SearchInput';
|
|
import StartScreen from './components/StartScreen';
|
|
import useApprovalsQuery from './hooks/useApprovalsQuery';
|
|
import useCoinBalanceQuery from './hooks/useCoinBalanceQuery';
|
|
|
|
const feature = config.features.marketplace;
|
|
const dappConfig = feature.isEnabled ? feature.essentialDapps?.revoke : undefined;
|
|
|
|
const defaultChainId = (
|
|
dappConfig?.chains.includes(config.chain.id as string) ?
|
|
config.chain.id :
|
|
dappConfig?.chains[0]
|
|
) as string;
|
|
|
|
const Revoke = () => {
|
|
const router = useRouter();
|
|
const { updateQuery } = useQueryParams();
|
|
const chainIdFromQuery: string | undefined = getQueryParamString(router.query.chainId);
|
|
const addressFromQuery = getQueryParamString(router.query.address);
|
|
const [ selectedChainId, setSelectedChainId ] = useState<Array<string>>([ chainIdFromQuery || defaultChainId ]);
|
|
const { address: connectedAddress } = useAccount();
|
|
const [ searchAddress, setSearchAddress ] = useState(addressFromQuery || '');
|
|
const [ searchInputValue, setSearchInputValue ] = useState('');
|
|
|
|
const selectedChain = essentialDappsChainsConfig()?.chains.find((chain) => chain.id === selectedChainId[0]);
|
|
|
|
const approvalsQuery = useApprovalsQuery(selectedChain, searchAddress);
|
|
const coinBalanceQuery = useCoinBalanceQuery(selectedChain, searchAddress);
|
|
const web3Wallet = useWeb3Wallet({ source: 'Essential dapps' });
|
|
const isMobile = useIsMobile();
|
|
|
|
const isValidAddress = useMemo(
|
|
() => isAddress(searchAddress.toLowerCase()),
|
|
[ searchAddress ],
|
|
);
|
|
|
|
const isAddressMatch = useMemo(
|
|
() => searchAddress.toLowerCase() === connectedAddress?.toLowerCase(),
|
|
[ searchAddress, connectedAddress ],
|
|
);
|
|
|
|
const handleChainValueChange = useCallback(({ value }: { value: Array<string> }) => {
|
|
setSelectedChainId(value);
|
|
mixpanel.logEvent(mixpanel.EventTypes.PAGE_WIDGET, {
|
|
Type: 'Chain switch',
|
|
Info: value[0],
|
|
Source: 'Revoke essential dapp',
|
|
});
|
|
updateQuery({ chainId: value[0] }, true);
|
|
}, [ updateQuery ]);
|
|
|
|
const handleSearch = useCallback(async(address: string) => {
|
|
if (address.endsWith('.eth')) {
|
|
try {
|
|
const ensAddress = await getEnsAddress(wagmiConfig.config, {
|
|
chainId: mainnet.id,
|
|
name: normalize(address),
|
|
});
|
|
if (ensAddress) {
|
|
address = ensAddress.toLowerCase();
|
|
}
|
|
} catch {}
|
|
}
|
|
setSearchAddress(address);
|
|
setSearchInputValue('');
|
|
if (isAddress(address.toLowerCase())) {
|
|
updateQuery({ address }, true);
|
|
}
|
|
}, [ updateQuery ]);
|
|
|
|
const handleAddressClick = useCallback(
|
|
(address: string) => () => {
|
|
handleSearch(address);
|
|
},
|
|
[ handleSearch ],
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (connectedAddress && !searchAddress) {
|
|
handleSearch(connectedAddress);
|
|
}
|
|
}, [ connectedAddress, handleSearch, searchAddress ]);
|
|
|
|
let content = <StartScreen/>;
|
|
|
|
if (searchAddress && selectedChainId) {
|
|
content = isValidAddress ? (
|
|
<Content
|
|
searchAddress={ searchAddress }
|
|
selectedChain={ selectedChain }
|
|
isAddressMatch={ isAddressMatch }
|
|
coinBalanceQuery={ coinBalanceQuery }
|
|
approvalsQuery={ approvalsQuery }
|
|
/>
|
|
) : (
|
|
<EmptyState
|
|
description={ `The input "${ searchAddress }" is not correct. Enter a correct 0x address to search` }
|
|
/>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="flex flex-col w-full gap-6 lg:gap-12">
|
|
<div className="flex flex-col w-full gap-3">
|
|
<SearchInput
|
|
value={ searchInputValue }
|
|
onChange={ setSearchInputValue }
|
|
onSubmit={ handleSearch }
|
|
/>
|
|
<div className="flex flex-col md:flex-row gap-3 justify-between">
|
|
<div
|
|
className="flex gap-3 items-center h-8 overflow-x-auto"
|
|
style={{ msOverflowStyle: 'none', scrollbarWidth: 'none' }}
|
|
>
|
|
<span className="text-sm font-medium text-[var(--color-text-secondary)]">
|
|
Examples
|
|
</span>
|
|
{ [
|
|
'0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
|
|
'0xFe89cc7aBB2C4183683ab71653C4cdc9B02D44b7',
|
|
'0xf6B6F07862A02C85628B3A9688beae07fEA9C863',
|
|
].slice(0, isMobile ? 2 : undefined).map((address) => (
|
|
<Button
|
|
key={ address }
|
|
variant="plain"
|
|
size="sm"
|
|
className="p-0"
|
|
onClick={ handleAddressClick(address) }
|
|
>
|
|
<AddressEntity
|
|
address={{ hash: address }}
|
|
truncation="constant"
|
|
noLink
|
|
noCopy
|
|
className="text-sm font-semibold"
|
|
/>
|
|
</Button>
|
|
)) }
|
|
</div>
|
|
<div className="flex gap-3 w-full md:w-auto">
|
|
{ connectedAddress ? (
|
|
<div className="flex gap-2 items-center shrink-0">
|
|
<span className="text-sm font-medium text-[var(--color-text-secondary)]">My wallet</span>
|
|
<Tooltip content="Click to see your approvals" disableOnMobile>
|
|
<Button
|
|
variant="plain"
|
|
size="sm"
|
|
className="p-0"
|
|
onClick={ handleAddressClick(connectedAddress) }
|
|
>
|
|
<AddressEntity
|
|
address={{ hash: connectedAddress }}
|
|
truncation="constant"
|
|
noTooltip
|
|
noLink
|
|
noCopy
|
|
className="text-sm font-semibold"
|
|
/>
|
|
</Button>
|
|
</Tooltip>
|
|
</div>
|
|
) : (
|
|
<Button
|
|
size="sm"
|
|
variant="outline"
|
|
onClick={ web3Wallet.connect }
|
|
loading={ web3Wallet.isOpen }
|
|
loadingText="Connect wallet"
|
|
className="shrink-0"
|
|
>
|
|
Connect wallet
|
|
</Button>
|
|
) }
|
|
<ChainSelect
|
|
value={ selectedChainId }
|
|
onValueChange={ handleChainValueChange }
|
|
mode="default"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{ content }
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Revoke;
|