feat: UI search on nfas list (#211)

* wip: created context for explore view

* feat: add search to context to filter on query

* feat: add search value to query

* feat: add search by name, external URL and ens

* feat: search by name

* chore: remove comments

* chore: rename files explore view (#217)

* chore: rename files explore view

* Update ui/src/views/explore/explore-list/results-search.tsx

Co-authored-by: Felipe Mendes <zo.fmendes@gmail.com>

* chore: rename nfa search fragment

---------

Co-authored-by: Felipe Mendes <zo.fmendes@gmail.com>

* chore: update setPageNumber

---------

Co-authored-by: Felipe Mendes <zo.fmendes@gmail.com>
This commit is contained in:
Camila Sosa Morales 2023-04-11 17:22:34 -03:00 committed by GitHub
parent e9275ed04f
commit 09e50adefc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 117 additions and 38 deletions

View File

@ -1,9 +1,10 @@
query lastNFAsPaginated($pageSize: Int, $skip: Int) { query lastNFAsPaginated($pageSize: Int, $skip: Int, $searchValue: String) {
tokens( tokens(
first: $pageSize first: $pageSize
skip: $skip skip: $skip
orderDirection: desc orderDirection: desc
orderBy: tokenId orderBy: tokenId
where: { name_contains_nocase: $searchValue }
) { ) {
id id
tokenId tokenId

View File

@ -1,7 +1,7 @@
import { Flex } from '@/components'; import { Flex } from '@/components';
import { styled } from '@/theme'; import { styled } from '@/theme';
export abstract class Header { export abstract class ExploreHeaderStyles {
static readonly Container = styled(Flex, { static readonly Container = styled(Flex, {
flexDirection: 'column', flexDirection: 'column',
gap: '$6', gap: '$6',

View File

@ -2,17 +2,17 @@ import { Link } from 'react-router-dom';
import { Button } from '@/components'; import { Button } from '@/components';
import { Header as HS } from './header.styles'; import { ExploreHeaderStyles as S } from './explore-header.styles';
export const Header: React.FC = () => ( export const ExploreHeader: React.FC = () => (
<HS.Container> <S.Container>
<HS.Text> <S.Text>
<HS.GrayText> <S.GrayText>
Created with a focus on decentralizing your applications, Created with a focus on decentralizing your applications,
</HS.GrayText> </S.GrayText>
<HS.WhiteText> NFAs are the only thing you need.</HS.WhiteText> <S.WhiteText> NFAs are the only thing you need.</S.WhiteText>
</HS.Text> </S.Text>
<HS.ButtonContainer> <S.ButtonContainer>
<Button as={Link} to="/mint" colorScheme="blue" variant="outline"> <Button as={Link} to="/mint" colorScheme="blue" variant="outline">
Create an NFA Create an NFA
</Button> </Button>
@ -20,6 +20,6 @@ export const Header: React.FC = () => (
<Button as={Link} to="/create-ap" colorScheme="gray" variant="outline"> <Button as={Link} to="/create-ap" colorScheme="gray" variant="outline">
Host an Access Point Host an Access Point
</Button> </Button>
</HS.ButtonContainer> </S.ButtonContainer>
</HS.Container> </S.Container>
); );

View File

@ -0,0 +1,16 @@
import { Flex } from '@/components';
import { Explore } from '../explore.context';
import { NFAListFragment } from './nfa-list';
import { NFASearchFragment } from './nfa-search';
export const ExploreListContainer: React.FC = () => {
return (
<Flex css={{ flexDirection: 'column' }}>
<Explore.Provider>
<NFASearchFragment />
<NFAListFragment />
</Explore.Provider>
</Flex>
);
};

View File

@ -0,0 +1 @@
export * from './explore-list-container';

View File

@ -1,10 +1,12 @@
import { useQuery } from '@apollo/client'; import { useQuery } from '@apollo/client';
import { useEffect, useState } from 'react'; import { useEffect } from 'react';
import { Flex, NFACard, NFACardSkeleton, NoResults } from '@/components'; import { Flex, NFACard, NFACardSkeleton, NoResults } from '@/components';
import { lastNFAsPaginatedDocument } from '@/graphclient'; import { lastNFAsPaginatedDocument } from '@/graphclient';
import { useWindowScrollEnd } from '@/hooks'; import { useWindowScrollEnd } from '@/hooks';
import { Explore } from '../../explore.context';
const pageSize = 10; //Set this size to test pagination const pageSize = 10; //Set this size to test pagination
const LoadingSkeletons: React.FC = () => ( const LoadingSkeletons: React.FC = () => (
@ -16,9 +18,9 @@ const LoadingSkeletons: React.FC = () => (
</> </>
); );
export const NFAList: React.FC = () => { export const NFAListFragment: React.FC = () => {
const [pageNumber, setPageNumber] = useState(0); const { endReached, pageNumber, search, setEndReached, setPageNumber } =
const [endReached, setEndReached] = useState(false); Explore.useContext();
const { const {
data: { tokens } = { tokens: [] }, data: { tokens } = { tokens: [] },
@ -28,7 +30,8 @@ export const NFAList: React.FC = () => {
fetchPolicy: 'cache-and-network', fetchPolicy: 'cache-and-network',
variables: { variables: {
pageSize, pageSize,
skip: pageNumber * pageSize, searchValue: search,
skip: pageNumber * pageSize, //skip is for the pagination
}, },
onCompleted: (data) => { onCompleted: (data) => {
if (data.tokens.length - tokens.length < pageSize) setEndReached(true); if (data.tokens.length - tokens.length < pageSize) setEndReached(true);
@ -43,7 +46,7 @@ export const NFAList: React.FC = () => {
useWindowScrollEnd(() => { useWindowScrollEnd(() => {
if (isLoading || endReached || queryError) return; if (isLoading || endReached || queryError) return;
setPageNumber((prevState) => prevState + 1); setPageNumber(pageNumber + 1);
}); });
if (queryError) return <div>Error</div>; //TODO handle error if (queryError) return <div>Error</div>; //TODO handle error

View File

@ -1,7 +1,9 @@
import { useState } from 'react'; import { useState } from 'react';
import { Dropdown, DropdownItem, Flex, Input } from '@/components'; import { Dropdown, DropdownItem, Flex, Input } from '@/components';
import { useDebounce } from '@/hooks';
import { Explore } from '../explore.context';
import { ResultsContainer, ResultsNumber, ResultsText } from './results.styles'; import { ResultsContainer, ResultsNumber, ResultsText } from './results.styles';
const orderResults: DropdownItem[] = [ const orderResults: DropdownItem[] = [
@ -9,11 +11,21 @@ const orderResults: DropdownItem[] = [
{ value: 'z-a', label: 'Sort Z-A' }, { value: 'z-a', label: 'Sort Z-A' },
]; ];
export const ResultsSearch: React.FC = () => { export const NFASearchFragment: React.FC = () => {
const { setSearch } = Explore.useContext();
const [selectedValue, setSelectedValue] = useState<DropdownItem>( const [selectedValue, setSelectedValue] = useState<DropdownItem>(
orderResults[0] orderResults[0]
); //TODO replace for context ); //TODO replace for context
const handleSearch = useDebounce(
(searchValue: string) => setSearch(searchValue),
200
);
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
handleSearch(e.target.value);
};
return ( return (
<Flex css={{ justifyContent: 'space-between' }}> <Flex css={{ justifyContent: 'space-between' }}>
<ResultsContainer> <ResultsContainer>
@ -25,6 +37,7 @@ export const ResultsSearch: React.FC = () => {
placeholder="Search" placeholder="Search"
leftIcon="search" leftIcon="search"
css={{ width: '23rem' }} css={{ width: '23rem' }}
onChange={handleSearchChange}
/> />
<Dropdown <Dropdown
items={orderResults} items={orderResults}

View File

@ -0,0 +1,59 @@
import { useState } from 'react';
import { OrderDirection } from '@/../.graphclient';
import { createContext } from '@/utils';
export type ExploreContext = {
search: string;
orderBy: string;
orderDirection: OrderDirection;
pageNumber: number;
endReached: boolean;
setSearch: (search: string) => void;
setOrderBy: (orderBy: string) => void;
setOrderDirection: (orderDirection: OrderDirection) => void;
setPageNumber: (pageNumber: number) => void;
setEndReached: (isEndReaced: boolean) => void;
};
const [ExploreProvider, useContext] = createContext<ExploreContext>({
name: 'Explore.Context',
hookName: 'Explore.useContext',
providerName: 'Explore.Provider',
});
export abstract class Explore {
static readonly useContext = useContext;
static readonly Provider: React.FC<Explore.ProviderProps> = ({
children,
}: Explore.ProviderProps) => {
const [search, setSearch] = useState('');
const [orderBy, setOrderBy] = useState('');
const [orderDirection, setOrderDirection] =
useState<OrderDirection>('desc');
const [pageNumber, setPageNumber] = useState(0);
const [endReached, setEndReached] = useState(false);
const context = {
search,
orderBy,
orderDirection,
pageNumber,
endReached,
setSearch,
setOrderBy,
setOrderDirection,
setPageNumber,
setEndReached,
};
return <ExploreProvider value={context}>{children}</ExploreProvider>;
};
}
export namespace Explore {
export type ProviderProps = {
children: React.ReactNode;
};
}

View File

@ -1,12 +1,12 @@
import { Explore as ES } from './explore.styles'; import { Explore as ES } from './explore.styles';
import { Header } from './header'; import { ExploreHeader } from './explore-header';
import { ListNfas } from './list-nfas'; import { ExploreListContainer } from './explore-list';
export const Explore: React.FC = () => { export const Explore: React.FC = () => {
return ( return (
<ES.Container> <ES.Container>
<Header /> <ExploreHeader />
<ListNfas /> <ExploreListContainer />
</ES.Container> </ES.Container>
); );
}; };

View File

@ -1 +0,0 @@
export * from './list-nfas';

View File

@ -1,13 +0,0 @@
import { Flex } from '@/components';
import { NFAList } from './nfa-list';
import { ResultsSearch } from './results-search';
export const ListNfas: React.FC = () => {
return (
<Flex css={{ flexDirection: 'column' }}>
<ResultsSearch />
<NFAList />
</Flex>
);
};