feat: NFA detail page subraph integration (#254)
* feat: nfa detail page with data from the subgraph * Update ui/src/views/indexed-nfa/fragments/aside.fragment.tsx Co-authored-by: Felipe Mendes <zo.fmendes@gmail.com> --------- Co-authored-by: Felipe Mendes <zo.fmendes@gmail.com>
This commit is contained in:
parent
85d14483cb
commit
393c4a316d
|
|
@ -38,7 +38,7 @@ query getLatestNFAs {
|
|||
}
|
||||
}
|
||||
|
||||
query getNFA($id: ID!) {
|
||||
query getNFADetail($id: ID!) {
|
||||
token(id: $id) {
|
||||
tokenId
|
||||
owner {
|
||||
|
|
@ -50,6 +50,33 @@ query getNFA($id: ID!) {
|
|||
externalURL
|
||||
logo
|
||||
color
|
||||
createdAt
|
||||
accessPoints {
|
||||
createdAt
|
||||
contentVerified
|
||||
owner {
|
||||
id
|
||||
}
|
||||
id
|
||||
}
|
||||
verified
|
||||
verifier {
|
||||
id
|
||||
}
|
||||
gitRepository {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query getNFA($id: ID!) {
|
||||
token(id: $id) {
|
||||
tokenId
|
||||
name
|
||||
ENS
|
||||
externalURL
|
||||
logo
|
||||
color
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,3 +10,45 @@ export const getRepoAndCommit = (url: string): object => {
|
|||
export const contractAddress = (address: string): string => {
|
||||
return `${address.slice(0, 6)}...${address.slice(-4)}`;
|
||||
};
|
||||
|
||||
export const getRepositoryFromURL = (url: string): string => {
|
||||
const urlSplitted = url.split('/');
|
||||
return `${urlSplitted[3]}/${urlSplitted[4]}`;
|
||||
};
|
||||
|
||||
export const getDate = (date: number): string => {
|
||||
return new Date(date * 1000).toLocaleDateString();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param date date in tiemstamp format
|
||||
* @returns time since date
|
||||
*/
|
||||
export const getTimeSince = (date: number): string => {
|
||||
const now = new Date().getTime(); //in timestamp format
|
||||
|
||||
const milliseconds = now - date * 1000;
|
||||
const seconds = milliseconds / 1000;
|
||||
const minutes = Math.round((seconds / 60) % 60);
|
||||
const days = Math.round(seconds / (60 * 60 * 24));
|
||||
const hours = Math.round(minutes % 60);
|
||||
const months = Math.round(days / 30.5);
|
||||
const years = Math.round(months / 12);
|
||||
|
||||
if (years > 0) {
|
||||
return `${years} year${years > 1 ? 's' : ''} ago`;
|
||||
}
|
||||
if (months > 0) {
|
||||
return `${months} month${months > 1 ? 's' : ''} ago`;
|
||||
}
|
||||
if (days > 0) {
|
||||
return `${days} day${days > 1 ? 's' : ''} ago`;
|
||||
}
|
||||
if (hours > 0) {
|
||||
return `${hours} hour${hours > 1 ? 's' : ''} ago`;
|
||||
}
|
||||
if (minutes > 0) {
|
||||
return `${minutes} min ago`;
|
||||
}
|
||||
return `${Math.round(seconds)} sec ago}`;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ export const CreateAccessPointFormBody: React.FC = () => {
|
|||
},
|
||||
onCompleted(data) {
|
||||
if (data.token && id) {
|
||||
const { name, tokenId, logo, color, externalURL: domain } = data.token;
|
||||
setNfa({ name, tokenId, logo, color, domain });
|
||||
const { name, tokenId, logo, color, externalURL } = data.token;
|
||||
setNfa({ name, tokenId, logo, color, externalURL });
|
||||
} else {
|
||||
AppLog.errorToast("We couldn't find the NFA you are looking for");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,17 +2,15 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { useState } from 'react';
|
||||
|
||||
import { Token } from '@/graphclient';
|
||||
import { EthereumHooks } from '@/integrations';
|
||||
import { useFleekERC721Billing } from '@/store';
|
||||
import { AppLog, createContext } from '@/utils';
|
||||
|
||||
export type NFA = {
|
||||
tokenId: string;
|
||||
name: string;
|
||||
logo: string;
|
||||
color: number;
|
||||
domain: string;
|
||||
};
|
||||
export type NFA = Pick<
|
||||
Token,
|
||||
'tokenId' | 'name' | 'logo' | 'color' | 'externalURL'
|
||||
>;
|
||||
|
||||
export type AccessPointContext = {
|
||||
billing: string | undefined;
|
||||
|
|
@ -43,7 +41,7 @@ export abstract class CreateAccessPoint {
|
|||
name: '',
|
||||
logo: '',
|
||||
color: 0,
|
||||
domain: '',
|
||||
externalURL: '',
|
||||
});
|
||||
|
||||
const value = {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Flex, Icon, Input } from '@/components';
|
||||
import { Flex, Icon } from '@/components';
|
||||
import { styled } from '@/theme';
|
||||
|
||||
export const NFASearchFragmentStyles = {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { useEffect, useMemo, useRef, useState } from 'react';
|
|||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { Button, Flex, Icon, NFAPreview } from '@/components';
|
||||
import { parseNumberToHexColor } from '@/utils/color';
|
||||
|
||||
import { IndexedNFA } from '../indexed-nfa.context';
|
||||
import { IndexedNFAStyles as S } from '../indexed-nfa.styles';
|
||||
|
|
@ -10,8 +11,7 @@ const Preview: React.FC = () => {
|
|||
const { nfa } = IndexedNFA.useContext();
|
||||
|
||||
const color = useMemo(
|
||||
// TODO: replace with util function
|
||||
() => `#${`000000${nfa.color.toString(16)}`.slice(-6)}`,
|
||||
() => `#${parseNumberToHexColor(nfa.color)}`,
|
||||
[nfa]
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useMemo } from 'react';
|
||||
|
||||
import { Flex, Icon, IconName, ResolvedAddress, Text } from '@/components';
|
||||
import { getDate, getRepositoryFromURL, getTimeSince } from '@/utils';
|
||||
|
||||
import { IndexedNFA } from '../indexed-nfa.context';
|
||||
import { IndexedNFAStyles as S } from '../indexed-nfa.styles';
|
||||
|
|
@ -33,10 +34,7 @@ const Header: React.FC = () => {
|
|||
|
||||
<S.Main.Divider.Elipse />
|
||||
|
||||
<HeaderData label="Created">
|
||||
{/* TODO: place correct data */}
|
||||
12/12/22
|
||||
</HeaderData>
|
||||
<HeaderData label="Created">{getDate(nfa.createdAt)}</HeaderData>
|
||||
|
||||
<S.Main.Divider.Elipse />
|
||||
|
||||
|
|
@ -81,14 +79,12 @@ const DataWrapper: React.FC<DataWrapperProps> = ({
|
|||
const Traits: React.FC = () => {
|
||||
const { nfa } = IndexedNFA.useContext();
|
||||
|
||||
// TODO: place correct data
|
||||
const traitsToShow = useMemo(() => {
|
||||
return [
|
||||
[nfa.ENS, 'ENS'],
|
||||
[nfa.gitRepository.id, 'Repository'],
|
||||
[10, 'Version'],
|
||||
[getRepositoryFromURL(nfa.gitRepository.id), 'Repository'],
|
||||
['', 'Version'],
|
||||
[nfa.externalURL, 'Domain'],
|
||||
[nfa.externalURL, 'Domain 2'],
|
||||
];
|
||||
}, [nfa]);
|
||||
|
||||
|
|
@ -137,29 +133,33 @@ const VerificationBanner: React.FC<VerificationBannerProps> = ({
|
|||
};
|
||||
|
||||
const Verification: React.FC = () => {
|
||||
const { nfa } = IndexedNFA.useContext();
|
||||
|
||||
return (
|
||||
<>
|
||||
<S.Main.SectionHeading>Verification</S.Main.SectionHeading>
|
||||
{/* TODO: Get verified from context */}
|
||||
<VerificationBanner verified={Math.random() > 0.5} />
|
||||
<VerificationBanner verified={nfa.verified} />
|
||||
<S.Main.DataList>
|
||||
{/* TODO: place correct data */}
|
||||
<DataWrapper label="Verifier">polygon.eth</DataWrapper>
|
||||
<DataWrapper label="Repository">polygon/fe</DataWrapper>
|
||||
<DataWrapper label="Verifier">
|
||||
{nfa.verifier ? (
|
||||
<ResolvedAddress>{nfa.verifier?.id}</ResolvedAddress>
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</DataWrapper>
|
||||
<DataWrapper label="Repository">
|
||||
{getRepositoryFromURL(nfa.gitRepository.id)}
|
||||
</DataWrapper>
|
||||
</S.Main.DataList>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// TODO: replace mocks with fetched data
|
||||
const apMocks = new Array(10).fill(0).map((_, index) => ({
|
||||
approved: Math.random() > 0.5,
|
||||
domain: `domain${index}.com`,
|
||||
owner: '0x7ED735b7095C05d78dF169F991f2b7f1A1F1A049',
|
||||
createdAt: `${Math.floor(Math.random() * 30)}m ago`,
|
||||
}));
|
||||
|
||||
const AccessPoints: React.FC = () => {
|
||||
const {
|
||||
nfa: { accessPoints },
|
||||
} = IndexedNFA.useContext();
|
||||
|
||||
return (
|
||||
<>
|
||||
<S.Main.SectionHeading>Frontends</S.Main.SectionHeading>
|
||||
|
|
@ -184,86 +184,33 @@ const AccessPoints: React.FC = () => {
|
|||
</S.Main.Table.Row>
|
||||
</S.Main.Table.Head>
|
||||
<S.Main.Table.Body>
|
||||
{apMocks.map((item) => (
|
||||
<S.Main.Table.Row key={item.domain}>
|
||||
<S.Main.Table.Data align="center">
|
||||
<S.Main.Table.Marker
|
||||
variant={item.approved ? 'active' : 'inactive'}
|
||||
/>
|
||||
</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>{item.domain}</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>
|
||||
<ResolvedAddress>{item.owner}</ResolvedAddress>
|
||||
</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>{item.createdAt}</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>
|
||||
<Icon name="external-link" />
|
||||
{accessPoints && accessPoints.length > 0 ? (
|
||||
accessPoints.map((item) => (
|
||||
<S.Main.Table.Row key={item.id}>
|
||||
<S.Main.Table.Data align="center">
|
||||
<S.Main.Table.Marker
|
||||
variant={item.contentVerified ? 'active' : 'inactive'}
|
||||
/>
|
||||
</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>{item.id}</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>
|
||||
<ResolvedAddress>{item.owner.id}</ResolvedAddress>
|
||||
</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>
|
||||
{getTimeSince(item.createdAt)}
|
||||
</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>
|
||||
<Icon name="external-link" />
|
||||
</S.Main.Table.Data>
|
||||
</S.Main.Table.Row>
|
||||
))
|
||||
) : (
|
||||
<S.Main.Table.Row>
|
||||
<S.Main.Table.Data align="center" colSpan={5}>
|
||||
<Text>No results</Text>
|
||||
</S.Main.Table.Data>
|
||||
</S.Main.Table.Row>
|
||||
))}
|
||||
</S.Main.Table.Body>
|
||||
</S.Main.Table.Root>
|
||||
</S.Main.Table.Container>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// TODO: replace mocks with fetched data
|
||||
const versionsMock = new Array(10).fill(0).map((_, index) => ({
|
||||
live: index === 0,
|
||||
commit: (Math.random() * 0xfffffffff).toString(16),
|
||||
preview: `test: subgraph matchstick tests for access points and acl refactor (#150
|
||||
)
|
||||
|
||||
* fix: errors from deprecated entities.`,
|
||||
time: `${Math.floor(Math.random() * 30)}m ago`,
|
||||
}));
|
||||
|
||||
const Versions: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<S.Main.SectionHeading>Versions</S.Main.SectionHeading>
|
||||
<S.Main.Table.Container>
|
||||
<S.Main.Table.Root>
|
||||
<colgroup>
|
||||
<col span={1} style={{ width: '9.5%' }} />
|
||||
<col span={1} style={{ width: '15%' }} />
|
||||
<col span={1} style={{ width: '50%' }} />
|
||||
<col span={1} style={{ width: '16%' }} />
|
||||
<col span={1} style={{ width: '9.5%' }} />
|
||||
</colgroup>
|
||||
<S.Main.Table.Head>
|
||||
<S.Main.Table.Row>
|
||||
<S.Main.Table.Data>
|
||||
<S.Main.Table.Marker />
|
||||
</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>Commit</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>Preview</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>Time</S.Main.Table.Data>
|
||||
<S.Main.Table.Data />
|
||||
</S.Main.Table.Row>
|
||||
</S.Main.Table.Head>
|
||||
<S.Main.Table.Body>
|
||||
{versionsMock.map((item) => (
|
||||
<S.Main.Table.Row key={item.commit}>
|
||||
<S.Main.Table.Data>
|
||||
<S.Main.Table.Marker
|
||||
variant={item.live ? 'active' : 'inactive'}
|
||||
text={item.live}
|
||||
>
|
||||
{item.live && 'Live'}
|
||||
</S.Main.Table.Marker>
|
||||
</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>{item.commit.slice(0, 6)}</S.Main.Table.Data>
|
||||
<S.Main.Table.Data title={item.preview}>
|
||||
{item.preview}
|
||||
</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>{item.time}</S.Main.Table.Data>
|
||||
<S.Main.Table.Data>
|
||||
<Icon name="external-link" />
|
||||
</S.Main.Table.Data>
|
||||
</S.Main.Table.Row>
|
||||
))}
|
||||
)}
|
||||
</S.Main.Table.Body>
|
||||
</S.Main.Table.Root>
|
||||
</S.Main.Table.Container>
|
||||
|
|
@ -279,7 +226,6 @@ export const IndexedNFAMainFragment: React.FC = () => {
|
|||
<Traits />
|
||||
<Verification />
|
||||
<AccessPoints />
|
||||
<Versions />
|
||||
</S.Main.Container>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ import { useQuery } from '@apollo/client';
|
|||
import { ethers } from 'ethers';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
import { getNFADocument } from '@/graphclient';
|
||||
import { NFAMock } from '@/mocks';
|
||||
import { getNFADetailDocument } from '@/graphclient';
|
||||
import { AppLog } from '@/utils';
|
||||
|
||||
import {
|
||||
|
|
@ -26,7 +25,7 @@ export const IndexedNFAView: React.FC = () => {
|
|||
navigate('/', { replace: true });
|
||||
};
|
||||
|
||||
const { loading, data = { token: {} } } = useQuery(getNFADocument, {
|
||||
const { loading, data = { token: {} } } = useQuery(getNFADetailDocument, {
|
||||
skip: id === undefined,
|
||||
variables: {
|
||||
id: ethers.utils.hexlify(Number(id)),
|
||||
|
|
@ -43,9 +42,13 @@ export const IndexedNFAView: React.FC = () => {
|
|||
return <IndexedNFASkeletonFragment />;
|
||||
}
|
||||
|
||||
// TODO: replace NFAMock with real data from useQuery
|
||||
if (!data.token) {
|
||||
//TODO add 404 page
|
||||
return <div>Token not found</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<IndexedNFA.Provider nfa={{ ...NFAMock, ...data.token }}>
|
||||
<IndexedNFA.Provider nfa={data.token}>
|
||||
<S.Grid>
|
||||
<IndexedNFAAsideFragment />
|
||||
<IndexedNFAMainFragment />
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
import { AppLog } from '@/utils';
|
||||
import { Mint } from '@/views/mint/mint.context';
|
||||
import { useMintFormContext } from '@/views/mint/nfa-step/form-step';
|
||||
|
||||
import { TextStyles } from './repo-branch-commit-fields.styles';
|
||||
|
||||
export const RepoBranchCommitFields: React.FC = () => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue