Commit a5682107 authored by Max Alekseenko's avatar Max Alekseenko Committed by GitHub

Merge pull request #1569 from blockscout/swap-button

Add swap button
parents 48f236e4 77ecda6c
...@@ -19,6 +19,7 @@ export { default as sentry } from './sentry'; ...@@ -19,6 +19,7 @@ export { default as sentry } from './sentry';
export { default as sol2uml } from './sol2uml'; export { default as sol2uml } from './sol2uml';
export { default as stats } from './stats'; export { default as stats } from './stats';
export { default as suave } from './suave'; export { default as suave } from './suave';
export { default as swapButton } from './swapButton';
export { default as txInterpretation } from './txInterpretation'; export { default as txInterpretation } from './txInterpretation';
export { default as userOps } from './userOps'; export { default as userOps } from './userOps';
export { default as verifiedTokens } from './verifiedTokens'; export { default as verifiedTokens } from './verifiedTokens';
......
import type { Feature } from './types';
import { getEnvValue } from '../utils';
import marketplace from './marketplace';
const value = getEnvValue('NEXT_PUBLIC_SWAP_BUTTON_URL');
const title = 'Swap button';
function isValidUrl(string: string) {
try {
new URL(string);
return true;
} catch (error) {
return false;
}
}
const config: Feature<{ dappId: string } | { url: string }> = (() => {
if (value) {
if (isValidUrl(value)) {
return Object.freeze({
title,
isEnabled: true,
url: value,
});
} else if (marketplace.isEnabled) {
return Object.freeze({
title,
isEnabled: true,
dappId: value,
});
}
}
return Object.freeze({
title,
isEnabled: false,
});
})();
export default config;
...@@ -52,3 +52,4 @@ NEXT_PUBLIC_STATS_API_HOST=https://stats-goerli.k8s-dev.blockscout.com ...@@ -52,3 +52,4 @@ NEXT_PUBLIC_STATS_API_HOST=https://stats-goerli.k8s-dev.blockscout.com
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.k8s-dev.blockscout.com NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.k8s-dev.blockscout.com
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info-test.k8s-dev.blockscout.com NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info-test.k8s-dev.blockscout.com
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs-test.k8s-dev.blockscout.com NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs-test.k8s-dev.blockscout.com
NEXT_PUBLIC_SWAP_BUTTON_URL=uniswap
...@@ -466,6 +466,7 @@ const schema = yup ...@@ -466,6 +466,7 @@ const schema = yup
NEXT_PUBLIC_OG_IMAGE_URL: yup.string().test(urlTest), NEXT_PUBLIC_OG_IMAGE_URL: yup.string().test(urlTest),
NEXT_PUBLIC_IS_SUAVE_CHAIN: yup.boolean(), NEXT_PUBLIC_IS_SUAVE_CHAIN: yup.boolean(),
NEXT_PUBLIC_HAS_USER_OPS: yup.boolean(), NEXT_PUBLIC_HAS_USER_OPS: yup.boolean(),
NEXT_PUBLIC_SWAP_BUTTON_URL: yup.string(),
// 6. External services envs // 6. External services envs
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: yup.string(), NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: yup.string(),
......
...@@ -53,3 +53,4 @@ NEXT_PUBLIC_VIEWS_TX_HIDDEN_FIELDS=['value','fee_currency','gas_price','tx_fee', ...@@ -53,3 +53,4 @@ NEXT_PUBLIC_VIEWS_TX_HIDDEN_FIELDS=['value','fee_currency','gas_price','tx_fee',
NEXT_PUBLIC_VISUALIZE_API_HOST=https://example.com NEXT_PUBLIC_VISUALIZE_API_HOST=https://example.com
NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET=false NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET=false
NEXT_PUBLIC_WEB3_WALLETS=['coinbase','metamask','token_pocket'] NEXT_PUBLIC_WEB3_WALLETS=['coinbase','metamask','token_pocket']
NEXT_PUBLIC_SWAP_BUTTON_URL=uniswap
...@@ -195,6 +195,7 @@ frontend: ...@@ -195,6 +195,7 @@ frontend:
NEXT_PUBLIC_ROLLUP_L1_BASE_URL: https://eth-goerli.blockscout.com/ NEXT_PUBLIC_ROLLUP_L1_BASE_URL: https://eth-goerli.blockscout.com/
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL: https://app.optimism.io/bridge/withdraw NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL: https://app.optimism.io/bridge/withdraw
NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62 NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62
NEXT_PUBLIC_SWAP_BUTTON_URL: sushiswap
envFromSecret: envFromSecret:
NEXT_PUBLIC_AUTH0_CLIENT_ID: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_AUTH0_CLIENT_ID NEXT_PUBLIC_AUTH0_CLIENT_ID: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_AUTH0_CLIENT_ID
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID
......
...@@ -165,6 +165,7 @@ frontend: ...@@ -165,6 +165,7 @@ frontend:
NEXT_PUBLIC_WEB3_WALLETS: "['token_pocket','coinbase','metamask']" NEXT_PUBLIC_WEB3_WALLETS: "['token_pocket','coinbase','metamask']"
NEXT_PUBLIC_VIEWS_NFT_MARKETPLACES: "[{'name':'LooksRare','collection_url':'https://goerli.looksrare.org/collections/{hash}','instance_url':'https://goerli.looksrare.org/collections/{hash}/{id}','logo_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/nft-marketplace-logos/looks-rare.png'}]" NEXT_PUBLIC_VIEWS_NFT_MARKETPLACES: "[{'name':'LooksRare','collection_url':'https://goerli.looksrare.org/collections/{hash}','instance_url':'https://goerli.looksrare.org/collections/{hash}/{id}','logo_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/nft-marketplace-logos/looks-rare.png'}]"
NEXT_PUBLIC_CONTRACT_CODE_IDES: "[{'title':'Remix IDE','url':'https://remix.blockscout.com/?address={hash}&blockscout=eth-goerli.blockscout.com','icon_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/ide-icons/remix.png'}]" NEXT_PUBLIC_CONTRACT_CODE_IDES: "[{'title':'Remix IDE','url':'https://remix.blockscout.com/?address={hash}&blockscout=eth-goerli.blockscout.com','icon_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/ide-icons/remix.png'}]"
NEXT_PUBLIC_SWAP_BUTTON_URL: uniswap
envFromSecret: envFromSecret:
NEXT_PUBLIC_SENTRY_DSN: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN NEXT_PUBLIC_SENTRY_DSN: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN
SENTRY_CSP_REPORT_URI: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/SENTRY_CSP_REPORT_URI SENTRY_CSP_REPORT_URI: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/SENTRY_CSP_REPORT_URI
......
...@@ -70,6 +70,7 @@ frontend: ...@@ -70,6 +70,7 @@ frontend:
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://app.optimism.io/bridge/withdraw NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL=https://app.optimism.io/bridge/withdraw
NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62 NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62
NEXT_PUBLIC_USE_NEXT_JS_PROXY: true NEXT_PUBLIC_USE_NEXT_JS_PROXY: true
NEXT_PUBLIC_SWAP_BUTTON_URL: sushiswap
envFromSecret: envFromSecret:
NEXT_PUBLIC_SENTRY_DSN: ref+vault://deployment-values/blockscout/dev/review-l2?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN NEXT_PUBLIC_SENTRY_DSN: ref+vault://deployment-values/blockscout/dev/review-l2?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN
SENTRY_CSP_REPORT_URI: ref+vault://deployment-values/blockscout/dev/review-l2?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/SENTRY_CSP_REPORT_URI SENTRY_CSP_REPORT_URI: ref+vault://deployment-values/blockscout/dev/review-l2?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/SENTRY_CSP_REPORT_URI
......
...@@ -76,6 +76,7 @@ frontend: ...@@ -76,6 +76,7 @@ frontend:
NEXT_PUBLIC_VIEWS_NFT_MARKETPLACES: "[{'name':'LooksRare','collection_url':'https://goerli.looksrare.org/collections/{hash}','instance_url':'https://goerli.looksrare.org/collections/{hash}/{id}','logo_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/nft-marketplace-logos/looks-rare.png'}]" NEXT_PUBLIC_VIEWS_NFT_MARKETPLACES: "[{'name':'LooksRare','collection_url':'https://goerli.looksrare.org/collections/{hash}','instance_url':'https://goerli.looksrare.org/collections/{hash}/{id}','logo_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/nft-marketplace-logos/looks-rare.png'}]"
NEXT_PUBLIC_HAS_USER_OPS: true NEXT_PUBLIC_HAS_USER_OPS: true
NEXT_PUBLIC_CONTRACT_CODE_IDES: "[{'title':'Remix IDE','url':'https://remix.blockscout.com/?address={hash}&blockscout=eth-goerli.blockscout.com','icon_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/ide-icons/remix.png'}]" NEXT_PUBLIC_CONTRACT_CODE_IDES: "[{'title':'Remix IDE','url':'https://remix.blockscout.com/?address={hash}&blockscout=eth-goerli.blockscout.com','icon_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/ide-icons/remix.png'}]"
NEXT_PUBLIC_SWAP_BUTTON_URL: uniswap
envFromSecret: envFromSecret:
NEXT_PUBLIC_SENTRY_DSN: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN NEXT_PUBLIC_SENTRY_DSN: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN
SENTRY_CSP_REPORT_URI: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/SENTRY_CSP_REPORT_URI SENTRY_CSP_REPORT_URI: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/SENTRY_CSP_REPORT_URI
......
...@@ -53,6 +53,7 @@ Please be aware that all environment variables prefixed with `NEXT_PUBLIC_` will ...@@ -53,6 +53,7 @@ Please be aware that all environment variables prefixed with `NEXT_PUBLIC_` will
- [SUAVE chain](ENVS.md#suave-chain) - [SUAVE chain](ENVS.md#suave-chain)
- [Sentry error monitoring](ENVS.md#sentry-error-monitoring) - [Sentry error monitoring](ENVS.md#sentry-error-monitoring)
- [OpenTelemetry](ENVS.md#opentelemetry) - [OpenTelemetry](ENVS.md#opentelemetry)
- [Swap button](ENVS.md#swap-button)
- [3rd party services configuration](ENVS.md#external-services-configuration) - [3rd party services configuration](ENVS.md#external-services-configuration)
&nbsp; &nbsp;
...@@ -591,6 +592,16 @@ OpenTelemetry SDK for Node.js app could be enabled by passing `OTEL_SDK_ENABLED= ...@@ -591,6 +592,16 @@ OpenTelemetry SDK for Node.js app could be enabled by passing `OTEL_SDK_ENABLED=
&nbsp; &nbsp;
### Swap button
If the feature is enabled, a Swap button will be displayed at the top of the explorer page, which will take you to the specified application in the marketplace or to an external site.
| Variable | Type| Description | Compulsoriness | Default value | Example value |
| --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_SWAP_BUTTON_URL | `string` | Application ID in the marketplace or website URL | - | - | `uniswap` |
&nbsp;
## External services configuration ## External services configuration
### Google ReCaptcha ### Google ReCaptcha
......
<svg viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.98 5.36c-.387 0-.645.258-.645.645a4.485 4.485 0 0 1-4.512 4.512h-.451c-.13 0-.194 0-.322-.064-.13 0-.194-.065-.323-.065-.064 0-.129-.064-.193-.064-.451-.129-.903-.387-1.29-.645-.064-.064-.128-.064-.128-.129-.065-.064-.13-.129-.194-.129-.129-.064-.258-.193-.322-.257l-.129-.13 1.16-.193a.669.669 0 0 0 .516-.773.669.669 0 0 0-.773-.516l-2.128.387-.515.129a.435.435 0 0 0-.387.258 1.195 1.195 0 0 0-.13.45l.517 2.708c.064.323.322.516.644.516h.13a.669.669 0 0 0 .515-.774l-.194-1.095c.13.128.323.257.452.386h.064c.065.065.129.13.193.13.13.128.258.193.452.257.129.258.322.322.515.451h.065c.064.065.193.065.322.13.258.064.516.128.71.193.128 0 .257.064.386.064h.774a5.778 5.778 0 0 0 5.801-5.801c.065-.323-.258-.58-.58-.58ZM.73 6.65c.387 0 .645-.258.645-.645a4.485 4.485 0 0 1 4.513-4.512h.45c.13 0 .194 0 .323.064.13 0 .194.065.323.065.064 0 .128.064.193.064.451.129.902.322 1.29.645.064.064.128.064.193.129.064.064.129.064.193.128.064.065.129.194.258.258l.129.13-1.16.193a.669.669 0 0 0-.516.773c.064.322.322.516.644.516h.13l2.707-.516a.669.669 0 0 0 .515-.773L11.045.526A.669.669 0 0 0 10.27.01a.669.669 0 0 0-.516.773L9.95 1.88c-.13-.129-.322-.322-.451-.386h-.065c-.064-.065-.129-.13-.193-.13-.13-.128-.258-.193-.451-.322-.194-.129-.387-.193-.58-.322h-.065C8.079.655 7.95.655 7.822.59a10.574 10.574 0 0 1-.71-.193c-.128 0-.257-.065-.386-.065h-.773A5.778 5.778 0 0 0 .15 6.134c-.064.258.194.516.58.516Z" fill="currentColor"/>
</svg>
...@@ -70,7 +70,7 @@ Type extends EventTypes.VERIFY_TOKEN ? { ...@@ -70,7 +70,7 @@ Type extends EventTypes.VERIFY_TOKEN ? {
'Action': 'Form opened' | 'Submit'; 'Action': 'Form opened' | 'Submit';
} : } :
Type extends EventTypes.WALLET_CONNECT ? { Type extends EventTypes.WALLET_CONNECT ? {
'Source': 'Header' | 'Smart contracts'; 'Source': 'Header' | 'Smart contracts' | 'Swap button';
'Status': 'Started' | 'Connected'; 'Status': 'Started' | 'Connected';
} : } :
Type extends EventTypes.WALLET_ACTION ? { Type extends EventTypes.WALLET_ACTION ? {
......
import type { NextRouter } from 'next/router';
export default function removeQueryParam(router: NextRouter, param: string) {
const { pathname, query } = router;
const newQuery = { ...query };
delete newQuery[param];
router.replace({ pathname, query: newQuery }, undefined, { shallow: true });
}
import type { NextRouter } from 'next/router';
export default function updateQueryParam(router: NextRouter, param: string, newValue: string) {
const { pathname, query } = router;
const newQuery = { ...query };
newQuery[param] = newValue;
router.replace({ pathname, query: newQuery }, undefined, { shallow: true });
}
...@@ -115,6 +115,7 @@ ...@@ -115,6 +115,7 @@
| "status/success" | "status/success"
| "status/warning" | "status/warning"
| "sun" | "sun"
| "swap"
| "testnet" | "testnet"
| "token-placeholder" | "token-placeholder"
| "token" | "token"
......
import { useRouter } from 'next/router';
import { useEffect, useRef } from 'react';
import removeQueryParam from 'lib/router/removeQueryParam';
import updateQueryParam from 'lib/router/updateQueryParam';
import useWallet from 'ui/snippets/walletMenu/useWallet';
export default function useAutoConnectWallet() {
const router = useRouter();
const { isWalletConnected, isModalOpen, connect } = useWallet({ source: 'Swap button' });
const isConnectionStarted = useRef(false);
useEffect(() => {
if (router.query.action !== 'connect') {
return;
}
let timer: ReturnType<typeof setTimeout>;
if (!isWalletConnected && !isModalOpen) {
if (!isConnectionStarted.current) {
timer = setTimeout(() => {
if (!isWalletConnected) {
connect();
isConnectionStarted.current = true;
}
}, 500);
} else {
isConnectionStarted.current = false;
updateQueryParam(router, 'action', 'tooltip');
}
} else if (isWalletConnected) {
isConnectionStarted.current = false;
removeQueryParam(router, 'action');
}
return () => clearTimeout(timer);
}, [ isWalletConnected, isModalOpen, connect, router ]);
}
...@@ -16,6 +16,7 @@ import * as metadata from 'lib/metadata'; ...@@ -16,6 +16,7 @@ import * as metadata from 'lib/metadata';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import ContentLoader from 'ui/shared/ContentLoader'; import ContentLoader from 'ui/shared/ContentLoader';
import useAutoConnectWallet from '../marketplace/useAutoConnectWallet';
import useMarketplaceWallet from '../marketplace/useMarketplaceWallet'; import useMarketplaceWallet from '../marketplace/useMarketplaceWallet';
const feature = config.features.marketplace; const feature = config.features.marketplace;
...@@ -96,6 +97,7 @@ const MarketplaceAppContent = ({ address, data, isPending }: Props) => { ...@@ -96,6 +97,7 @@ const MarketplaceAppContent = ({ address, data, isPending }: Props) => {
const MarketplaceApp = () => { const MarketplaceApp = () => {
const { address, sendTransaction, signMessage, signTypedData } = useMarketplaceWallet(); const { address, sendTransaction, signMessage, signTypedData } = useMarketplaceWallet();
useAutoConnectWallet();
const apiFetch = useApiFetch(); const apiFetch = useApiFetch();
const router = useRouter(); const router = useRouter();
......
import { Button, Box } from '@chakra-ui/react';
import React from 'react';
import { route } from 'nextjs-routes';
import config from 'configs/app';
import IconSvg from 'ui/shared/IconSvg';
const feature = config.features.swapButton;
const SwapButton = () => {
if (!feature.isEnabled) {
return null;
}
const href = 'url' in feature ?
feature.url :
route({ pathname: '/apps/[id]', query: { id: feature.dappId, action: 'connect' } });
return (
<Button
as="a"
href={ href }
target={ 'url' in feature ? '_blank' : '_self' }
variant="solid"
size="xs"
borderRadius="sm"
height={ 5 }
px={ 1.5 }
>
<IconSvg name="swap" boxSize={ 3 } mr={{ base: 0, sm: 1 }}/>
<Box display={{ base: 'none', sm: 'inline' }}>
Swap
</Box>
</Button>
);
};
export default React.memo(SwapButton);
import { test, expect } from '@playwright/experimental-ct-react'; import { test as base, expect } from '@playwright/experimental-ct-react';
import React from 'react'; import React from 'react';
import * as statsMock from 'mocks/stats/index'; import * as statsMock from 'mocks/stats/index';
import contextWithEnvs from 'playwright/fixtures/contextWithEnvs';
import TestApp from 'playwright/TestApp'; import TestApp from 'playwright/TestApp';
import buildApiUrl from 'playwright/utils/buildApiUrl'; import buildApiUrl from 'playwright/utils/buildApiUrl';
import TopBar from './TopBar'; import TopBar from './TopBar';
const test = base.extend({
context: contextWithEnvs([
{ name: 'NEXT_PUBLIC_SWAP_BUTTON_URL', value: 'uniswap' },
// eslint-disable-next-line @typescript-eslint/no-explicit-any
]) as any,
});
test('default view +@dark-mode +@mobile', async({ mount, page }) => { test('default view +@dark-mode +@mobile', async({ mount, page }) => {
await page.route(buildApiUrl('homepage_stats'), (route) => route.fulfill({ await page.route(buildApiUrl('homepage_stats'), (route) => route.fulfill({
status: 200, status: 200,
......
import { Flex, useColorModeValue } from '@chakra-ui/react'; import { Flex, Divider, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import config from 'configs/app';
import ColorModeSwitch from './ColorModeSwitch'; import ColorModeSwitch from './ColorModeSwitch';
import SwapButton from './SwapButton';
import TopBarStats from './TopBarStats'; import TopBarStats from './TopBarStats';
const feature = config.features.swapButton;
const TopBar = () => { const TopBar = () => {
const bgColor = useColorModeValue('gray.50', 'whiteAlpha.100'); const bgColor = useColorModeValue('gray.50', 'whiteAlpha.100');
...@@ -13,9 +18,18 @@ const TopBar = () => { ...@@ -13,9 +18,18 @@ const TopBar = () => {
px={ 6 } px={ 6 }
bgColor={ bgColor } bgColor={ bgColor }
justifyContent="space-between" justifyContent="space-between"
alignItems="center"
> >
<TopBarStats/> <TopBarStats/>
<ColorModeSwitch/> <Flex alignItems="center">
{ feature.isEnabled && (
<>
<SwapButton/>
<Divider mr={ 3 } ml={{ base: 2, sm: 3 }} height={ 4 } orientation="vertical"/>
</>
) }
<ColorModeSwitch/>
</Flex>
</Flex> </Flex>
); );
}; };
......
...@@ -3,6 +3,7 @@ import { useRouter } from 'next/router'; ...@@ -3,6 +3,7 @@ import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import { SECOND } from 'lib/consts'; import { SECOND } from 'lib/consts';
import removeQueryParam from 'lib/router/removeQueryParam';
type Props = { type Props = {
children: React.ReactNode; children: React.ReactNode;
...@@ -29,14 +30,28 @@ const WalletTooltip = ({ children, isDisabled, isMobile }: Props) => { ...@@ -29,14 +30,28 @@ const WalletTooltip = ({ children, isDisabled, isMobile }: Props) => {
React.useEffect(() => { React.useEffect(() => {
const wasShown = window.localStorage.getItem(localStorageKey); const wasShown = window.localStorage.getItem(localStorageKey);
const isMarketplacePage = [ '/apps', '/apps/[id]' ].includes(router.pathname); const isMarketplacePage = [ '/apps', '/apps/[id]' ].includes(router.pathname);
if (!isDisabled && !wasShown && isMarketplacePage) { const isTooltipShowAction = router.query.action === 'tooltip';
setTimeout(() => { const isConnectWalletAction = router.query.action === 'connect';
const needToShow = (!wasShown && !isConnectWalletAction) || isTooltipShowAction;
let timer1: ReturnType<typeof setTimeout>;
let timer2: ReturnType<typeof setTimeout>;
if (!isDisabled && isMarketplacePage && needToShow) {
timer1 = setTimeout(() => {
setIsTooltipShown.on(); setIsTooltipShown.on();
window.localStorage.setItem(localStorageKey, 'true'); window.localStorage.setItem(localStorageKey, 'true');
setTimeout(() => setIsTooltipShown.off(), 5 * SECOND); timer2 = setTimeout(() => setIsTooltipShown.off(), 5 * SECOND);
}, SECOND); if (isTooltipShowAction) {
removeQueryParam(router, 'action');
}
}, isTooltipShowAction ? 0 : SECOND);
} }
}, [ setIsTooltipShown, localStorageKey, isDisabled, router.pathname ]);
return () => {
clearTimeout(timer1);
clearTimeout(timer2);
};
}, [ setIsTooltipShown, localStorageKey, isDisabled, router ]);
return ( return (
<Tooltip <Tooltip
......
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