From d0535d5b198d6c4772e7acb2455dc05f6a0a926e Mon Sep 17 00:00:00 2001 From: Henry Palacios Date: Tue, 12 Oct 2021 22:11:03 -0300 Subject: [PATCH 1/5] Adding logic in useSearchSubmit --- .../components/common/Search/index.tsx | 2 +- src/hooks/useSearchSubmit.ts | 13 +++- src/utils/miscellaneous.ts | 14 +++++ test/hooks/useSearchSubmit.test.tsx | 51 ++++++++++++++++ test/utils/miscellaneous.spec.ts | 60 ++++++++++++++++++- 5 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 test/hooks/useSearchSubmit.test.tsx diff --git a/src/apps/explorer/components/common/Search/index.tsx b/src/apps/explorer/components/common/Search/index.tsx index 5c3916eb2..1fe368998 100644 --- a/src/apps/explorer/components/common/Search/index.tsx +++ b/src/apps/explorer/components/common/Search/index.tsx @@ -25,7 +25,7 @@ export const Search: React.FC = () => { name="query" value={query} onChange={(e): void => setQuery(e.target.value.trim())} - placeholder="Search by order ID" + placeholder="Search by order ID / Address" aria-label="Search the GP explorer for orders, batches and transactions" /> diff --git a/src/hooks/useSearchSubmit.ts b/src/hooks/useSearchSubmit.ts index 698b53af1..12fafe16c 100644 --- a/src/hooks/useSearchSubmit.ts +++ b/src/hooks/useSearchSubmit.ts @@ -1,5 +1,16 @@ import { useCallback } from 'react' import { useHistory } from 'react-router-dom' +import { isAnAddressAccount, isAnOrderId } from 'utils' + +export function pathAccordingTo(query: string): string { + if (isAnAddressAccount(query)) { + return 'address' + } else if (isAnOrderId(query)) { + return 'orders' + } + + return 'search' +} export function useSearchSubmit(): (query: string) => void { const history = useHistory() @@ -8,7 +19,7 @@ export function useSearchSubmit(): (query: string) => void { (query: string) => { // For now assumes /orders/ path. Needs logic to try all types for a valid response: // Orders, transactions, tokens, batches - query && query.length > 0 && history.push(`/orders/${query}`) + query && query.length > 0 && history.push(`/${pathAccordingTo(query)}/${query}`) }, [history], ) diff --git a/src/utils/miscellaneous.ts b/src/utils/miscellaneous.ts index 05d0b594d..ba62e597c 100644 --- a/src/utils/miscellaneous.ts +++ b/src/utils/miscellaneous.ts @@ -252,3 +252,17 @@ export async function timeout(params: TimeoutParams): Promise { // no defined result -- throw message throw new Error(timeoutMsg) } + +/** + * Check if a string is an orderId against regex + * + * @param text Possible OrderId string to check + */ +export const isAnOrderId = (text: string): boolean => text.match(/^0x[a-fA-F0-9]{112}$/)?.input !== undefined + +/** + * Check if string is an address account against regex + * + * @param text Possible address string to check + */ +export const isAnAddressAccount = (text: string): boolean => text.match(/^0x[a-fA-F0-9]{40}$/)?.input !== undefined diff --git a/test/hooks/useSearchSubmit.test.tsx b/test/hooks/useSearchSubmit.test.tsx new file mode 100644 index 000000000..84f0cfa69 --- /dev/null +++ b/test/hooks/useSearchSubmit.test.tsx @@ -0,0 +1,51 @@ +import React from 'react' +import { createMemoryHistory, MemoryHistory } from 'history' +import { Router } from 'react-router-dom' +import { renderHook, act } from '@testing-library/react-hooks' + +import { useSearchSubmit } from 'hooks/useSearchSubmit' + +interface Props { + children?: React.ReactNode + history: MemoryHistory +} + +function wrapperMemoryRouter(props: Props): JSX.Element { + return ( + <> + {props.children} + + ) +} + +describe('useSearchSubmit', () => { + it('should be /search/... with invalid search', () => { + const query = 'invalid_search' + const history = createMemoryHistory() + + const { result } = renderHook(() => useSearchSubmit(), { + wrapper: ({ children }) => wrapperMemoryRouter({ children, history }), + }) + + act(() => { + result.current(query) + }) + + expect(history.location.pathname).toBe(`/search/${query}`) + }) + + it('should be /address/0x... when address string is valid', () => { + const query = '0xb6BAd41ae76A11D10f7b0E664C5007b908bC77C9' + const history = createMemoryHistory() + + const { result } = renderHook(() => useSearchSubmit(), { + wrapper: ({ children }) => wrapperMemoryRouter({ children, history }), + }) + + act(() => { + result.current(query) + }) + + expect(history.location.pathname).toBe(`/address/${query}`) + }) +}) diff --git a/test/utils/miscellaneous.spec.ts b/test/utils/miscellaneous.spec.ts index 68cb6a79a..36d172405 100644 --- a/test/utils/miscellaneous.spec.ts +++ b/test/utils/miscellaneous.spec.ts @@ -1,6 +1,7 @@ import { tokenList } from '../data' -import { getToken } from 'utils' +import { getToken, isAnAddressAccount, isAnOrderId } from 'utils' import BN from 'bn.js' +import { pathAccordingTo } from 'hooks/useSearchSubmit' describe('getToken', () => { describe('empty cases', () => { @@ -89,3 +90,60 @@ describe('getToken', () => { }) }) }) + +describe('isAnOrderId', () => { + it('should be an orderId', () => { + const text = + '0x405bd0278c11399f84f10e19fb9b45123996e7d0a68a60ddebc3b9581576b484ff714b8b0e2700303ec912bd40496c3997ceea2b614b17d9' + + const result = isAnOrderId(text) + + expect(result).toBe(true) + }) + + it('not be an orderId', () => { + const text = '0xb6BAd41ae76A11D10f7b0E664C5007b908bC77C9' + + const result = isAnOrderId(text) + + expect(result).toBe(false) + }) +}) + +describe('isAnAddressAccount', () => { + it('should be an address', () => { + const text = '0xb6BAd41ae76A11D10f7b0E664C5007b908bC77C9' + + const result = isAnAddressAccount(text) + + expect(result).toBe(true) + }) + + it('not be an address', () => { + const text = + '0x405bd0278c11399F84f10e19fb9b45123996e7d0a68a60ddebc3b9581576b484ff714b8b0e2700303ec912bd40496c3997ceea2b614b17d9' + + const result = isAnAddressAccount(text) + + expect(result).toBe(false) + }) +}) + +describe('pathAccordingTo', () => { + it('should return the search word when it does not match', () => { + const text = 'Invalid Search' + + const result = pathAccordingTo(text) + + expect(result).toBe('search') + }) + + it('should return the orders word when it match', () => { + const text = + '0x405bd0278c11399f84f10e19fb9b45123996e7d0a68a60ddebc3b9581576b484ff714b8b0e2700303ec912bd40496c3997ceea2b614b17d9' + + const result = pathAccordingTo(text) + + expect(result).toBe('orders') + }) +}) From acb591aae29ce0f00cd6e42984db35da871dd5c5 Mon Sep 17 00:00:00 2001 From: Henry Palacios Date: Wed, 13 Oct 2021 13:34:01 -0300 Subject: [PATCH 2/5] Keep orders/ and network, update h1 and placeholders --- src/apps/explorer/pages/Home/index.tsx | 2 +- src/components/orders/OrderNotFound/index.tsx | 2 +- src/hooks/useSearchSubmit.ts | 18 +++++++++++------- test/hooks/useSearchSubmit.test.tsx | 4 ++-- test/utils/miscellaneous.spec.ts | 11 +++++------ 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/apps/explorer/pages/Home/index.tsx b/src/apps/explorer/pages/Home/index.tsx index 89d2af526..ee9eccfbf 100644 --- a/src/apps/explorer/pages/Home/index.tsx +++ b/src/apps/explorer/pages/Home/index.tsx @@ -27,7 +27,7 @@ const Wrapper = styled.div` export const Home: React.FC = () => { return ( -

Search Order ID

+

Search Order ID / Address

) diff --git a/src/components/orders/OrderNotFound/index.tsx b/src/components/orders/OrderNotFound/index.tsx index 50e8fff75..261b73848 100644 --- a/src/components/orders/OrderNotFound/index.tsx +++ b/src/components/orders/OrderNotFound/index.tsx @@ -1,7 +1,7 @@ import React from 'react' import { useParams } from 'react-router' import styled from 'styled-components' -import { Search } from 'components/orders/Search' +import { Search } from 'apps/explorer/components/common/Search' import SupportIcon from 'assets/img/support.png' import { MEDIA } from 'const' diff --git a/src/hooks/useSearchSubmit.ts b/src/hooks/useSearchSubmit.ts index 12fafe16c..6b377d9c0 100644 --- a/src/hooks/useSearchSubmit.ts +++ b/src/hooks/useSearchSubmit.ts @@ -1,26 +1,30 @@ import { useCallback } from 'react' import { useHistory } from 'react-router-dom' -import { isAnAddressAccount, isAnOrderId } from 'utils' +import { isAnAddressAccount } from 'utils' +import { usePathPrefix } from 'state/network' export function pathAccordingTo(query: string): string { + let path = 'orders' if (isAnAddressAccount(query)) { - return 'address' - } else if (isAnOrderId(query)) { - return 'orders' + path = 'address' } - return 'search' + return path } export function useSearchSubmit(): (query: string) => void { const history = useHistory() + const prefixNetwork = usePathPrefix() return useCallback( (query: string) => { // For now assumes /orders/ path. Needs logic to try all types for a valid response: // Orders, transactions, tokens, batches - query && query.length > 0 && history.push(`/${pathAccordingTo(query)}/${query}`) + const path = pathAccordingTo(query) + const pathPrefix = prefixNetwork ? `${prefixNetwork}/${path}` : `${path}` + + query && query.length > 0 && history.push(`/${pathPrefix}/${query}`) }, - [history], + [history, prefixNetwork], ) } diff --git a/test/hooks/useSearchSubmit.test.tsx b/test/hooks/useSearchSubmit.test.tsx index 84f0cfa69..20ad6fbad 100644 --- a/test/hooks/useSearchSubmit.test.tsx +++ b/test/hooks/useSearchSubmit.test.tsx @@ -19,7 +19,7 @@ function wrapperMemoryRouter(props: Props): JSX.Element { } describe('useSearchSubmit', () => { - it('should be /search/... with invalid search', () => { + it('should be /orders/... with invalid search', () => { const query = 'invalid_search' const history = createMemoryHistory() @@ -31,7 +31,7 @@ describe('useSearchSubmit', () => { result.current(query) }) - expect(history.location.pathname).toBe(`/search/${query}`) + expect(history.location.pathname).toBe(`/orders/${query}`) }) it('should be /address/0x... when address string is valid', () => { diff --git a/test/utils/miscellaneous.spec.ts b/test/utils/miscellaneous.spec.ts index 36d172405..49a05d34b 100644 --- a/test/utils/miscellaneous.spec.ts +++ b/test/utils/miscellaneous.spec.ts @@ -130,20 +130,19 @@ describe('isAnAddressAccount', () => { }) describe('pathAccordingTo', () => { - it('should return the search word when it does not match', () => { + it('should return the orders word when it does not match', () => { const text = 'Invalid Search' const result = pathAccordingTo(text) - expect(result).toBe('search') + expect(result).toBe('orders') }) - it('should return the orders word when it match', () => { - const text = - '0x405bd0278c11399f84f10e19fb9b45123996e7d0a68a60ddebc3b9581576b484ff714b8b0e2700303ec912bd40496c3997ceea2b614b17d9' + it('should return the address word when it match', () => { + const text = '0xb6BAd41ae76A11D10f7b0E664C5007b908bC77C9' const result = pathAccordingTo(text) - expect(result).toBe('orders') + expect(result).toBe('address') }) }) From 1f2133ad8aca80e18ac3aa2802b0ca89e24c032c Mon Sep 17 00:00:00 2001 From: Henry Palacios Date: Wed, 13 Oct 2021 16:15:25 -0300 Subject: [PATCH 3/5] Fix Search bar style --- .../components/common/Search/Search.styled.ts | 15 +++++++++++---- .../explorer/components/common/Search/index.tsx | 4 +++- src/apps/explorer/pages/Home/index.tsx | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/apps/explorer/components/common/Search/Search.styled.ts b/src/apps/explorer/components/common/Search/Search.styled.ts index a9cf36002..af224fff9 100644 --- a/src/apps/explorer/components/common/Search/Search.styled.ts +++ b/src/apps/explorer/components/common/Search/Search.styled.ts @@ -1,11 +1,18 @@ -import styled from 'styled-components' +import styled, { css, FlattenSimpleInterpolation } from 'styled-components' import SVG from 'react-inlinesvg' export const Wrapper = styled.form` display: flex; - width: 100%; - max-width: 50rem; - margin: 0 auto; + ${({ className }): FlattenSimpleInterpolation => + className === 'home' + ? css` + width: 100%; + max-width: 50rem; + margin: 0 auto; + ` + : css` + width: 60rem; + `} position: relative; ` diff --git a/src/apps/explorer/components/common/Search/index.tsx b/src/apps/explorer/components/common/Search/index.tsx index 1fe368998..2b4eae464 100644 --- a/src/apps/explorer/components/common/Search/index.tsx +++ b/src/apps/explorer/components/common/Search/index.tsx @@ -5,9 +5,10 @@ import { useSearchSubmit } from 'hooks/useSearchSubmit' // assets import searchImg from 'assets/img/search2.svg' -export const Search: React.FC = () => { +export const Search: React.FC> = (props) => { const [query, setQuery] = useState('') const handleSubmit = useSearchSubmit() + const { className } = props return ( { e.preventDefault() handleSubmit(query) }} + className={className} > - setQuery(e.target.value.trim())} - placeholder="Search by order ID" - aria-label="Search the GP explorer for orders, batches and transactions" - /> - - ) -} From d3b868e0cf15163b46a87b71d7498a30d19f92e3 Mon Sep 17 00:00:00 2001 From: Henry Palacios Date: Thu, 14 Oct 2021 10:40:05 -0300 Subject: [PATCH 5/5] Improve sentences in tests and placeholder --- src/apps/explorer/components/common/Search/index.tsx | 2 +- test/utils/miscellaneous.spec.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/apps/explorer/components/common/Search/index.tsx b/src/apps/explorer/components/common/Search/index.tsx index 2b4eae464..2380b792b 100644 --- a/src/apps/explorer/components/common/Search/index.tsx +++ b/src/apps/explorer/components/common/Search/index.tsx @@ -27,7 +27,7 @@ export const Search: React.FC> = (props) => name="query" value={query} onChange={(e): void => setQuery(e.target.value.trim())} - placeholder="Search by order ID / Address" + placeholder="Search by Order ID / Address" aria-label="Search the GP explorer for orders, batches and transactions" /> diff --git a/test/utils/miscellaneous.spec.ts b/test/utils/miscellaneous.spec.ts index 49a05d34b..8ad9b7a8f 100644 --- a/test/utils/miscellaneous.spec.ts +++ b/test/utils/miscellaneous.spec.ts @@ -92,7 +92,7 @@ describe('getToken', () => { }) describe('isAnOrderId', () => { - it('should be an orderId', () => { + test('Is orderId', () => { const text = '0x405bd0278c11399f84f10e19fb9b45123996e7d0a68a60ddebc3b9581576b484ff714b8b0e2700303ec912bd40496c3997ceea2b614b17d9' @@ -101,7 +101,7 @@ describe('isAnOrderId', () => { expect(result).toBe(true) }) - it('not be an orderId', () => { + test('Is not orderId', () => { const text = '0xb6BAd41ae76A11D10f7b0E664C5007b908bC77C9' const result = isAnOrderId(text) @@ -111,7 +111,7 @@ describe('isAnOrderId', () => { }) describe('isAnAddressAccount', () => { - it('should be an address', () => { + test('Is an Address account', () => { const text = '0xb6BAd41ae76A11D10f7b0E664C5007b908bC77C9' const result = isAnAddressAccount(text) @@ -119,7 +119,7 @@ describe('isAnAddressAccount', () => { expect(result).toBe(true) }) - it('not be an address', () => { + test('Is not an Address account', () => { const text = '0x405bd0278c11399F84f10e19fb9b45123996e7d0a68a60ddebc3b9581576b484ff714b8b0e2700303ec912bd40496c3997ceea2b614b17d9'