chore: UI setup subgraph querying (#152)

* wip: querying with graph-client and apollo

* feat: fetching last nfts minted with basic pagination

* chore: add .graphclient folder to gitignore and update readme

* chore: teste pagination

* chore: add create ap button in NFA

* chore: remove unsued files

* fix: fix CI

* Update test.yml

* chore: add config to handle graphclient imports

* chore: update queries

* chore: update list nfa views

* chore: add graphql folder. remove unused env variable
This commit is contained in:
Camila Sosa Morales 2023-03-08 15:28:16 -05:00 committed by GitHub
parent 7387b68571
commit 9db81d2025
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 2599 additions and 510 deletions

View File

@ -29,8 +29,10 @@ jobs:
- name: Install Dependencies - name: Install Dependencies
run: yarn --ignore-scripts run: yarn --ignore-scripts
- name: Create .graphclient folder - name: Create .graphclient folder
run: yarn graphclient build run: yarn graphclient build
- name: Audit - name: Audit
run: yarn audit --groups dependencies run: yarn audit --groups dependencies

1
ui/.gitignore vendored
View File

@ -1 +1,2 @@
dist dist
.graphclient

10
ui/.graphclientrc.yml Normal file
View File

@ -0,0 +1,10 @@
# .graphclientrc.yml
sources:
- name: FleekNFA
handler:
graphql:
endpoint: https://api.thegraph.com/subgraphs/name/emperororokusaki/flk-test-subgraph #replace for nfa subgraph
documents:
- ./graphql/*.graphql

View File

@ -23,11 +23,14 @@ To run the UI localy follow the steps:
```bash ```bash
$ yarn $ yarn
``` ```
3. To use ConnecKit is neccessary get an [Alchemy ID](https://alchemy.com/), so create an App and get the credentials. Then set the following .env file 3. To use ConnecKit is neccessary get an [Alchemy ID](https://alchemy.com/), so create an App and get the credentials. Then set the following .env file
```bash ```bash
VITE_ALCHEMY_API_KEY VITE_ALCHEMY_API_KEY
VITE_ALCHEMY_APP_NAME VITE_ALCHEMY_APP_NAME
``` ```
Also, you'll need to set up your firebase cretendials to make work the github login. Add to the .env file the following variables Also, you'll need to set up your firebase cretendials to make work the github login. Add to the .env file the following variables
```bash ```bash
@ -42,7 +45,13 @@ To run the UI localy follow the steps:
Get them from the project settings on the firebase dashboard. Read [this article](https://support.google.com/firebase/answer/7015592?hl=en#zippy=%2Cin-this-article) to know how to get your porject config Get them from the project settings on the firebase dashboard. Read [this article](https://support.google.com/firebase/answer/7015592?hl=en#zippy=%2Cin-this-article) to know how to get your porject config
4. Start the local server running the app: 4. Build the queries to run the project:
```bash
$ yarn graphclient build
```
5. Start the local server running the app:
```bash ```bash
$ yarn dev $ yarn dev

View File

@ -0,0 +1,20 @@
query lastMintsPaginated($pageSize: Int, $skip: Int) {
newMints(
first: $pageSize
skip: $skip
orderDirection: desc
orderBy: tokenId
) {
id
tokenId
description
name
}
}
query totalTokens {
tokens {
id
}
}

View File

@ -6,14 +6,17 @@
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"dev:css": "tailwindcss -o ./tailwind.css --watch && yarn dev", "dev:css": "tailwindcss -o ./tailwind.css --watch && yarn dev",
"build": "vite build", "build": "yarn graphclient build && vite build",
"postinstall": "graphclient build",
"preview": "vite preview", "preview": "vite preview",
"storybook": "export SET NODE_OPTIONS=--openssl-legacy-provider && start-storybook -p 6006", "storybook": "export SET NODE_OPTIONS=--openssl-legacy-provider && start-storybook -p 6006",
"build-storybook": "build-storybook" "build-storybook": "build-storybook"
}, },
"author": "Fleek", "author": "Fleek",
"dependencies": { "dependencies": {
"@apollo/client": "^3.7.9",
"@ethersproject/providers": "^5.7.2", "@ethersproject/providers": "^5.7.2",
"@graphprotocol/client-apollo": "^1.0.16",
"@headlessui/react": "^1.7.8", "@headlessui/react": "^1.7.8",
"@radix-ui/colors": "^0.1.8", "@radix-ui/colors": "^0.1.8",
"@radix-ui/react-avatar": "^1.0.1", "@radix-ui/react-avatar": "^1.0.1",
@ -26,6 +29,7 @@
"connectkit": "^1.1.3", "connectkit": "^1.1.3",
"firebase": "^9.17.1", "firebase": "^9.17.1",
"formik": "^2.2.9", "formik": "^2.2.9",
"graphql": "^16.6.0",
"octokit": "^2.0.14", "octokit": "^2.0.14",
"path": "^0.12.7", "path": "^0.12.7",
"react": "^18.2.0", "react": "^18.2.0",
@ -38,6 +42,7 @@
"@babel/core": "^7.20.12", "@babel/core": "^7.20.12",
"@esbuild-plugins/node-globals-polyfill": "^0.1.1", "@esbuild-plugins/node-globals-polyfill": "^0.1.1",
"@esbuild-plugins/node-modules-polyfill": "^0.2.2", "@esbuild-plugins/node-modules-polyfill": "^0.2.2",
"@graphprotocol/client-cli": "^2.2.19",
"@storybook/addon-actions": "^6.5.15", "@storybook/addon-actions": "^6.5.15",
"@storybook/addon-essentials": "^6.5.15", "@storybook/addon-essentials": "^6.5.15",
"@storybook/addon-interactions": "^6.5.15", "@storybook/addon-interactions": "^6.5.15",

View File

@ -4,6 +4,7 @@ import { ComponentsTest, Home, Mint } from './views';
import { SVGTestScreen } from './views/svg-test'; // TODO: remove when done import { SVGTestScreen } from './views/svg-test'; // TODO: remove when done
import { ConnectKitButton } from 'connectkit'; import { ConnectKitButton } from 'connectkit';
import { MintTest } from './views/mint-test'; import { MintTest } from './views/mint-test';
import { CreateAP } from './views/access-point';
export const App = () => { export const App = () => {
themeGlobals(); themeGlobals();
@ -18,6 +19,7 @@ export const App = () => {
<Route path="/home" element={<Home />} /> <Route path="/home" element={<Home />} />
<Route path="/mint" element={<Mint />} /> <Route path="/mint" element={<Mint />} />
<Route path="/svg" element={<SVGTestScreen />} /> <Route path="/svg" element={<SVGTestScreen />} />
<Route path="/create-ap/:id" element={<CreateAP />} />
{/** TODO remove for release */} {/** TODO remove for release */}
<Route path="/components-test" element={<ComponentsTest />} /> <Route path="/components-test" element={<ComponentsTest />} />
<Route path="/mint-test" element={<MintTest />} /> <Route path="/mint-test" element={<MintTest />} />

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,20 @@
import React from 'react';
import {
ApolloClient,
InMemoryCache,
ApolloProvider as Provider,
} from '@apollo/client';
import { GraphApolloLink } from '@graphprotocol/client-apollo';
import * as GraphClient from '@/graphclient';
const client = new ApolloClient({
link: new GraphApolloLink(GraphClient),
cache: new InMemoryCache(),
});
type ApolloProviderProps = {
children: React.ReactNode;
};
export const ApolloProvider: React.FC<ApolloProviderProps> = ({ children }) => {
return <Provider client={client}>{children}</Provider>;
};

View File

@ -1,3 +1,4 @@
import { ApolloProvider } from './apollo-provider';
import { ConnectkitProvider } from './connectkit-provider'; import { ConnectkitProvider } from './connectkit-provider';
import { ReactQueryProvider } from './react-query-provider'; import { ReactQueryProvider } from './react-query-provider';
import { ReduxProvider } from './redux-provider'; import { ReduxProvider } from './redux-provider';
@ -10,7 +11,9 @@ export const Providers: React.FC<ProviderProps> = ({ children }) => {
return ( return (
<ReduxProvider> <ReduxProvider>
<ReactQueryProvider> <ReactQueryProvider>
<ConnectkitProvider>{children}</ConnectkitProvider> <ApolloProvider>
<ConnectkitProvider>{children}</ConnectkitProvider>
</ApolloProvider>
</ReactQueryProvider> </ReactQueryProvider>
</ReduxProvider> </ReduxProvider>
); );

View File

@ -0,0 +1,6 @@
import { useParams } from 'react-router-dom';
export const CreateAP = () => {
const { id } = useParams();
return <>Token to create AP:{id}</>;
};

View File

@ -0,0 +1 @@
export * from './create-ap';

View File

@ -1,7 +1,15 @@
import { Flex } from '@/components';
import { Link } from 'react-router-dom';
import { NFAList } from './nfa-list/nfa-list';
export const Home = () => { export const Home = () => {
return ( return (
<> <Flex css={{ flexDirection: 'column', margin: '$60' }}>
<h1>Home</h1> <h1>Home</h1>
</> <Link to="/mint">
<u>Mint NFA!</u>
</Link>
<NFAList />
</Flex>
); );
}; };

View File

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

View File

@ -0,0 +1,90 @@
import { lastMintsPaginatedDocument, totalTokensDocument } from '@/graphclient';
import { Button, Card, Flex, NoResults } from '@/components';
import { FleekERC721 } from '@/integrations/ethereum/contracts';
import { useQuery } from '@apollo/client';
import { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
const pageSize = 10; //Set this size to test pagination
export const NFAList = () => {
const [pageNumber, setPageNumber] = useState(1);
const [totalPages, setTotalPages] = useState(0);
const {
data: totalTokens,
loading: loadingTotalTokens,
error: errorTotalTokens,
} = useQuery(totalTokensDocument);
const {
data: dataMintedTokens,
loading: loadingMintedTokens,
error: errorMintedTokens,
} = useQuery(lastMintsPaginatedDocument, {
variables: {
//first page is 0
pageSize,
skip: pageNumber > 0 ? (pageNumber - 1) * pageSize : pageNumber,
},
});
useEffect(() => {
if (totalTokens && totalTokens.tokens.length > 0) {
setTotalPages(Math.ceil(totalTokens.tokens.length / pageSize));
}
}, [totalTokens]);
if (loadingMintedTokens || loadingTotalTokens) return <div>Loading...</div>; //TODO handle loading
if (errorMintedTokens || errorTotalTokens) return <div>Error</div>; //TODO handle error
const handlePreviousPage = () => {
if (pageNumber > 1) {
setPageNumber((prevState) => prevState - 1);
}
};
const handleNextPage = () => {
if (pageNumber + 1 <= totalPages)
setPageNumber((prevState) => prevState + 1);
};
return (
<Flex css={{ flexDirection: 'column', margin: '$5', gap: '$2' }}>
<Flex css={{ gap: '$2' }}>
{/* TODO this will be remove when we have pagination component */}
<span>items per page: {pageSize}</span>
<span>
page: {pageNumber}/{totalPages}
</span>
<Button onClick={handlePreviousPage} disabled={pageNumber === 1}>
Previous page
</Button>
<Button onClick={handleNextPage} disabled={pageNumber === totalPages}>
Next page
</Button>
</Flex>
<Flex css={{ gap: '$2' }}>
{dataMintedTokens && dataMintedTokens.newMints.length > 0 ? (
dataMintedTokens.newMints.map((mint) => (
<Card.Container key={mint.tokenId}>
<Card.Heading title={mint.name} />
<Card.Body css={{ display: 'flex', flexDirection: 'column' }}>
<a
target="_blank"
href={`https://testnets.opensea.io/assets/mumbai/${FleekERC721.address}/${mint.tokenId}`}
>
<u>Open NFA on Opensea</u>
</a>
<Link to={`/create-ap/${mint.tokenId}`}>Create AP</Link>
</Card.Body>
</Card.Container>
))
) : (
<NoResults />
)}
</Flex>
</Flex>
);
};

View File

@ -7,7 +7,9 @@
"rootDirs": ["src"], "rootDirs": ["src"],
"baseUrl": "src", "baseUrl": "src",
"paths": { "paths": {
"@/*": ["*"] "@/*": ["*"],
"@/graphclient": ["../.graphclient"],
"@/graphclient/*": ["../.graphclient/*"]
}, },
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"resolveJsonModule": true, "resolveJsonModule": true,
@ -21,5 +23,5 @@
"isolatedModules": true, "isolatedModules": true,
"types": ["vite/client"] "types": ["vite/client"]
}, },
"include": ["./src", "./*.ts"] "include": ["./src", "./.graphclient", "./*.ts"]
} }

File diff suppressed because it is too large Load Diff