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:
parent
e9275ed04f
commit
09e50adefc
|
|
@ -1,9 +1,10 @@
|
|||
query lastNFAsPaginated($pageSize: Int, $skip: Int) {
|
||||
query lastNFAsPaginated($pageSize: Int, $skip: Int, $searchValue: String) {
|
||||
tokens(
|
||||
first: $pageSize
|
||||
skip: $skip
|
||||
orderDirection: desc
|
||||
orderBy: tokenId
|
||||
where: { name_contains_nocase: $searchValue }
|
||||
) {
|
||||
id
|
||||
tokenId
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Flex } from '@/components';
|
||||
import { styled } from '@/theme';
|
||||
|
||||
export abstract class Header {
|
||||
export abstract class ExploreHeaderStyles {
|
||||
static readonly Container = styled(Flex, {
|
||||
flexDirection: 'column',
|
||||
gap: '$6',
|
||||
|
|
@ -2,17 +2,17 @@ import { Link } from 'react-router-dom';
|
|||
|
||||
import { Button } from '@/components';
|
||||
|
||||
import { Header as HS } from './header.styles';
|
||||
import { ExploreHeaderStyles as S } from './explore-header.styles';
|
||||
|
||||
export const Header: React.FC = () => (
|
||||
<HS.Container>
|
||||
<HS.Text>
|
||||
<HS.GrayText>
|
||||
export const ExploreHeader: React.FC = () => (
|
||||
<S.Container>
|
||||
<S.Text>
|
||||
<S.GrayText>
|
||||
Created with a focus on decentralizing your applications,
|
||||
</HS.GrayText>
|
||||
<HS.WhiteText> NFAs are the only thing you need.</HS.WhiteText>
|
||||
</HS.Text>
|
||||
<HS.ButtonContainer>
|
||||
</S.GrayText>
|
||||
<S.WhiteText> NFAs are the only thing you need.</S.WhiteText>
|
||||
</S.Text>
|
||||
<S.ButtonContainer>
|
||||
<Button as={Link} to="/mint" colorScheme="blue" variant="outline">
|
||||
Create an NFA
|
||||
</Button>
|
||||
|
|
@ -20,6 +20,6 @@ export const Header: React.FC = () => (
|
|||
<Button as={Link} to="/create-ap" colorScheme="gray" variant="outline">
|
||||
Host an Access Point
|
||||
</Button>
|
||||
</HS.ButtonContainer>
|
||||
</HS.Container>
|
||||
</S.ButtonContainer>
|
||||
</S.Container>
|
||||
);
|
||||
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1 @@
|
|||
export * from './explore-list-container';
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
import { useQuery } from '@apollo/client';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { Flex, NFACard, NFACardSkeleton, NoResults } from '@/components';
|
||||
import { lastNFAsPaginatedDocument } from '@/graphclient';
|
||||
import { useWindowScrollEnd } from '@/hooks';
|
||||
|
||||
import { Explore } from '../../explore.context';
|
||||
|
||||
const pageSize = 10; //Set this size to test pagination
|
||||
|
||||
const LoadingSkeletons: React.FC = () => (
|
||||
|
|
@ -16,9 +18,9 @@ const LoadingSkeletons: React.FC = () => (
|
|||
</>
|
||||
);
|
||||
|
||||
export const NFAList: React.FC = () => {
|
||||
const [pageNumber, setPageNumber] = useState(0);
|
||||
const [endReached, setEndReached] = useState(false);
|
||||
export const NFAListFragment: React.FC = () => {
|
||||
const { endReached, pageNumber, search, setEndReached, setPageNumber } =
|
||||
Explore.useContext();
|
||||
|
||||
const {
|
||||
data: { tokens } = { tokens: [] },
|
||||
|
|
@ -28,7 +30,8 @@ export const NFAList: React.FC = () => {
|
|||
fetchPolicy: 'cache-and-network',
|
||||
variables: {
|
||||
pageSize,
|
||||
skip: pageNumber * pageSize,
|
||||
searchValue: search,
|
||||
skip: pageNumber * pageSize, //skip is for the pagination
|
||||
},
|
||||
onCompleted: (data) => {
|
||||
if (data.tokens.length - tokens.length < pageSize) setEndReached(true);
|
||||
|
|
@ -43,7 +46,7 @@ export const NFAList: React.FC = () => {
|
|||
|
||||
useWindowScrollEnd(() => {
|
||||
if (isLoading || endReached || queryError) return;
|
||||
setPageNumber((prevState) => prevState + 1);
|
||||
setPageNumber(pageNumber + 1);
|
||||
});
|
||||
|
||||
if (queryError) return <div>Error</div>; //TODO handle error
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
import { useState } from 'react';
|
||||
|
||||
import { Dropdown, DropdownItem, Flex, Input } from '@/components';
|
||||
import { useDebounce } from '@/hooks';
|
||||
|
||||
import { Explore } from '../explore.context';
|
||||
import { ResultsContainer, ResultsNumber, ResultsText } from './results.styles';
|
||||
|
||||
const orderResults: DropdownItem[] = [
|
||||
|
|
@ -9,11 +11,21 @@ const orderResults: DropdownItem[] = [
|
|||
{ 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>(
|
||||
orderResults[0]
|
||||
); //TODO replace for context
|
||||
|
||||
const handleSearch = useDebounce(
|
||||
(searchValue: string) => setSearch(searchValue),
|
||||
200
|
||||
);
|
||||
|
||||
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
handleSearch(e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<Flex css={{ justifyContent: 'space-between' }}>
|
||||
<ResultsContainer>
|
||||
|
|
@ -25,6 +37,7 @@ export const ResultsSearch: React.FC = () => {
|
|||
placeholder="Search"
|
||||
leftIcon="search"
|
||||
css={{ width: '23rem' }}
|
||||
onChange={handleSearchChange}
|
||||
/>
|
||||
<Dropdown
|
||||
items={orderResults}
|
||||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
import { Explore as ES } from './explore.styles';
|
||||
import { Header } from './header';
|
||||
import { ListNfas } from './list-nfas';
|
||||
import { ExploreHeader } from './explore-header';
|
||||
import { ExploreListContainer } from './explore-list';
|
||||
|
||||
export const Explore: React.FC = () => {
|
||||
return (
|
||||
<ES.Container>
|
||||
<Header />
|
||||
<ListNfas />
|
||||
<ExploreHeader />
|
||||
<ExploreListContainer />
|
||||
</ES.Container>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
export * from './list-nfas';
|
||||
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
Loading…
Reference in New Issue