Commit c175ca12 authored by tom goriunov's avatar tom goriunov Committed by GitHub

Allow adding capability to display alert/announcement in the new UI (#1232)

* Allow adding capability to display alert/announcement in the new UI

Fixes #1123

* fix tests
parent 6575bdfd
......@@ -39,6 +39,9 @@ const UI = Object.freeze({
indexingAlert: {
isHidden: getEnvValue('NEXT_PUBLIC_HIDE_INDEXING_ALERT'),
},
maintenanceAlert: {
message: getEnvValue(process.env.NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE),
},
explorers: {
items: parseEnvJson<Array<NetworkExplorer>>(getEnvValue('NEXT_PUBLIC_NETWORK_EXPLORERS')) || [],
},
......
......@@ -32,6 +32,7 @@ NEXT_PUBLIC_GIT_TAG=v1.0.11
## views
## misc
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}]
NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE=
# app features
NEXT_PUBLIC_APP_ENV=testing
......
......@@ -304,6 +304,7 @@ const schema = yup
.json()
.of(networkExplorerSchema),
NEXT_PUBLIC_HIDE_INDEXING_ALERT: yup.boolean(),
NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE: yup.string(),
// 5. Features configuration
NEXT_PUBLIC_API_SPEC_URL: yup.string().url(),
......
......@@ -190,6 +190,7 @@ Settings for meta tags and OG tags
| --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_NETWORK_EXPLORERS | `Array<NetworkExplorer>` where `NetworkExplorer` can have following [properties](#network-explorer-configuration-properties) | Used to build up links to transactions, blocks, addresses in other chain explorers. | - | - | `[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/tx'}}]` |
| NEXT_PUBLIC_HIDE_INDEXING_ALERT | `boolean` | Set to `true` to hide indexing alert, if the chain indexing isn't completed | - | `false` | `true` |
| NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE | `string` | Used for displaying custom announcements or alerts in the header of the site. Could be a regular string or a HTML code. | - | - | `Hello world! 🤪` |
#### Network explorer configuration properties
......
......@@ -3,7 +3,6 @@ import { useRouter } from 'next/router';
import type { FormEvent } from 'react';
import React from 'react';
import IndexingAlertBlocks from 'ui/home/IndexingAlertBlocks';
import useMarketplaceApps from 'ui/marketplace/useMarketplaceApps';
import SearchResultListItem from 'ui/searchResults/SearchResultListItem';
import SearchResultsInput from 'ui/searchResults/SearchResultsInput';
......@@ -17,6 +16,7 @@ import PageTitle from 'ui/shared/Page/PageTitle';
import Pagination from 'ui/shared/pagination/Pagination';
import Thead from 'ui/shared/TheadSticky';
import Header from 'ui/snippets/header/Header';
import HeaderAlert from 'ui/snippets/header/HeaderAlert';
import useSearchQuery from 'ui/snippets/searchBar/useSearchQuery';
const SearchResultsPageContent = () => {
......@@ -181,7 +181,7 @@ const SearchResultsPageContent = () => {
return (
<>
<IndexingAlertBlocks/>
<HeaderAlert/>
<Header renderSearchBar={ renderSearchBar }/>
<AppErrorBoundary>
<Layout.Content>
......
import { test, expect } from '@playwright/experimental-ct-react';
import { test as base, expect } from '@playwright/experimental-ct-react';
import React from 'react';
import contextWithEnvs from 'playwright/fixtures/contextWithEnvs';
import TestApp from 'playwright/TestApp';
import buildApiUrl from 'playwright/utils/buildApiUrl';
......@@ -8,6 +9,16 @@ import Layout from './Layout';
const API_URL = buildApiUrl('homepage_indexing_status');
const test = base.extend({
context: contextWithEnvs([
{
name: 'NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE',
value: 'We are currently lacking pictures of <i>ducks</i>. Please <a href="mailto:duck@blockscout.com">send</a> us one.',
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
]) as any,
});
test('base view +@mobile', async({ mount, page }) => {
await page.route(API_URL, (route) => route.fulfill({
status: 200,
......
......@@ -2,9 +2,9 @@ import React from 'react';
import type { Props } from './types';
import IndexingAlertBlocks from 'ui/home/IndexingAlertBlocks';
import AppErrorBoundary from 'ui/shared/AppError/AppErrorBoundary';
import Header from 'ui/snippets/header/Header';
import HeaderAlert from 'ui/snippets/header/HeaderAlert';
import * as Layout from './components';
......@@ -14,7 +14,7 @@ const LayoutDefault = ({ children }: Props) => {
<Layout.MainArea>
<Layout.SideBar/>
<Layout.MainColumn>
<IndexingAlertBlocks/>
<HeaderAlert/>
<Header/>
<AppErrorBoundary>
<Layout.Content>
......
......@@ -2,9 +2,9 @@ import React from 'react';
import type { Props } from './types';
import IndexingAlertBlocks from 'ui/home/IndexingAlertBlocks';
import AppErrorBoundary from 'ui/shared/AppError/AppErrorBoundary';
import Header from 'ui/snippets/header/Header';
import HeaderAlert from 'ui/snippets/header/HeaderAlert';
import * as Layout from './components';
......@@ -14,7 +14,7 @@ const LayoutError = ({ children }: Props) => {
<Layout.MainArea>
<Layout.SideBar/>
<Layout.MainColumn>
<IndexingAlertBlocks/>
<HeaderAlert/>
<Header/>
<AppErrorBoundary>
<main>
......
......@@ -2,9 +2,9 @@ import React from 'react';
import type { Props } from './types';
import IndexingAlertBlocks from 'ui/home/IndexingAlertBlocks';
import AppErrorBoundary from 'ui/shared/AppError/AppErrorBoundary';
import Header from 'ui/snippets/header/Header';
import HeaderAlert from 'ui/snippets/header/HeaderAlert';
import * as Layout from './components';
......@@ -16,7 +16,7 @@ const LayoutHome = ({ children }: Props) => {
<Layout.MainColumn
paddingTop={{ base: '88px', lg: 9 }}
>
<IndexingAlertBlocks/>
<HeaderAlert/>
<Header isHomePage/>
<AppErrorBoundary>
{ children }
......
......@@ -15,11 +15,11 @@ import type { ResourceError } from 'lib/api/resources';
import useApiQuery from 'lib/api/useApiQuery';
import useFetch from 'lib/hooks/useFetch';
import useIssueUrl from 'lib/hooks/useIssueUrl';
import IndexingAlertIntTxs from 'ui/home/IndexingAlertIntTxs';
import NetworkAddToWallet from 'ui/shared/NetworkAddToWallet';
import ColorModeToggler from '../header/ColorModeToggler';
import FooterLinkItem from './FooterLinkItem';
import IntTxsIndexingStatus from './IntTxsIndexingStatus';
import getApiVersionUrl from './utils/getApiVersionUrl';
const MAX_LINKS_COLUMNS = 3;
......@@ -109,7 +109,7 @@ const Footer = () => {
<Box flexGrow="1" mb={{ base: 8, lg: 0 }}>
<Flex flexWrap="wrap" columnGap={ 8 } rowGap={ 6 }>
<ColorModeToggler/>
{ !config.UI.indexingAlert.isHidden && <IndexingAlertIntTxs/> }
{ !config.UI.indexingAlert.isHidden && <IntTxsIndexingStatus/> }
<NetworkAddToWallet/>
</Flex>
<Box mt={{ base: 5, lg: '44px' }}>
......
......@@ -11,7 +11,7 @@ import { apos, nbsp, ndash } from 'lib/html-entities';
import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage';
const IndexingAlertIntTxs = () => {
const IntTxsIndexingStatus = () => {
const { data, isError, isLoading } = useApiQuery('homepage_indexing_status');
......@@ -98,4 +98,4 @@ const IndexingAlertIntTxs = () => {
);
};
export default IndexingAlertIntTxs;
export default IntTxsIndexingStatus;
import { Flex } from '@chakra-ui/react';
import React from 'react';
import IndexingBlocksAlert from './alerts/IndexingBlocksAlert';
import MaintenanceAlert from './alerts/MaintenanceAlert';
const HeaderAlert = () => {
return (
<Flex flexDir="column" rowGap={ 3 } mb={ 6 } _empty={{ display: 'none' }}>
<MaintenanceAlert/>
<IndexingBlocksAlert/>
</Flex>
);
};
export default React.memo(HeaderAlert);
import { Alert, AlertIcon, AlertTitle, chakra, Skeleton } from '@chakra-ui/react';
import { Alert, AlertIcon, AlertTitle, Skeleton } from '@chakra-ui/react';
import { useQueryClient } from '@tanstack/react-query';
import React from 'react';
......@@ -8,14 +8,11 @@ import type { IndexingStatus } from 'types/api/indexingStatus';
import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery';
import { useAppContext } from 'lib/contexts/app';
import * as cookies from 'lib/cookies';
import useIsMobile from 'lib/hooks/useIsMobile';
import { nbsp, ndash } from 'lib/html-entities';
import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage';
const IndexingAlertBlocks = ({ className }: { className?: string }) => {
const isMobile = useIsMobile();
const IndexingBlocksAlert = () => {
const appProps = useAppContext();
const cookiesString = appProps.cookies;
const [ hasAlertCookie ] = React.useState(cookies.get(cookies.NAMES.INDEXING_ALERT, cookiesString) === 'true');
......@@ -57,7 +54,7 @@ const IndexingAlertBlocks = ({ className }: { className?: string }) => {
}
if (isLoading) {
return hasAlertCookie ? <Skeleton h={{ base: '96px', lg: '48px' }} mb={ 6 } w="100%" className={ className }/> : null;
return hasAlertCookie ? <Skeleton h={{ base: '96px', lg: '48px' }} mb={ 6 } w="100%"/> : null;
}
if (data.finished_indexing_blocks !== false) {
......@@ -65,8 +62,8 @@ const IndexingAlertBlocks = ({ className }: { className?: string }) => {
}
return (
<Alert status="info" colorScheme="gray" py={ 3 } borderRadius="12px" mb={ 6 } className={ className }>
{ !isMobile && <AlertIcon/> }
<Alert status="info" colorScheme="gray" py={ 3 } borderRadius="md">
<AlertIcon display={{ base: 'none', lg: 'flex' }}/>
<AlertTitle>
{ `${ data.indexed_blocks_ratio && `${ Math.floor(Number(data.indexed_blocks_ratio) * 100) }% Blocks Indexed${ nbsp }${ ndash } ` }
We're indexing this chain right now. Some of the counts may be inaccurate.` }
......@@ -75,4 +72,4 @@ const IndexingAlertBlocks = ({ className }: { className?: string }) => {
);
};
export default chakra(IndexingAlertBlocks);
export default React.memo(IndexingBlocksAlert);
import { Alert, AlertIcon, AlertTitle } from '@chakra-ui/react';
import React from 'react';
import config from 'configs/app';
const MaintenanceAlert = () => {
if (!config.UI.maintenanceAlert.message) {
return null;
}
return (
<Alert status="info" colorScheme="gray" py={ 3 } borderRadius="md">
<AlertIcon display={{ base: 'none', lg: 'flex' }}/>
<AlertTitle
dangerouslySetInnerHTML={{ __html: config.UI.maintenanceAlert.message }}
sx={{
'& a': {
color: 'link',
_hover: {
color: 'link_hovered',
},
},
}}
/>
</Alert>
);
};
export default MaintenanceAlert;
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