Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/server/app/[domain]/page-component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ const NFTCard = (props: { asset: FuelAsset }) => {
queryFn: async (): Promise<Record<string, string>> => {
let metadata: Record<string, string> = defaultMetadata ?? {};
const metadataEntries = Object.entries(metadata).filter(
([key]) => !key.toLowerCase().includes('uri')
([key]) => !['uri', 'image'].includes(key.toLowerCase())
);

if (metadataEntries.length === 0 && uri?.endsWith('.json')) {
Expand Down
1 change: 1 addition & 0 deletions apps/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@wagmi/core": "2.13.4",
"date-fns": "^3.6.0",
"dayjs": "^1.11.11",
"ethers": "^6.13.5",
"framer-motion": "^11.3.4",
"fuels": "0.100.1",
"lodash": "^4.17.21",
Expand Down
12 changes: 9 additions & 3 deletions apps/ui/src/components/card/accountsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { NSDialog } from '../../modules/ens/components/dialog';
interface AccountsCardProps {
metadata: { key: string; value: string | undefined }[] | undefined;
addAction: () => void;
isMetadataLoading: boolean;
}

const EmptyAccounts = ({ ensAction }: { ensAction: () => void }) => {
Expand Down Expand Up @@ -49,7 +50,11 @@ const EmptyAccounts = ({ ensAction }: { ensAction: () => void }) => {
);
};

export const AccountsCard = ({ metadata, addAction }: AccountsCardProps) => {
export const AccountsCard = ({
metadata,
addAction,
isMetadataLoading,
}: AccountsCardProps) => {
const { isMyDomain } = useSidebar();
const ensDialogState = useDisclosure();

Expand Down Expand Up @@ -93,7 +98,7 @@ export const AccountsCard = ({ metadata, addAction }: AccountsCardProps) => {
</Flex>

{metadata?.filter(
(data) => !avoidKeys.includes(data.key as MetadataKeys),
(data) => !avoidKeys.includes(data.key as MetadataKeys)
).length ? (
<VStack spacing={5} h="full" mt={6}>
{metadata?.map((m) => {
Expand All @@ -104,11 +109,12 @@ export const AccountsCard = ({ metadata, addAction }: AccountsCardProps) => {
key={m.key}
value={m.value}
variant={variant}
isMetadataLoading={isMetadataLoading}
isVerified
rightAddon
rightAddonName={getInputIcon(
m.key as MetadataKeys,
m.value ?? '',
m.value ?? ''
)}
/>
);
Expand Down
27 changes: 20 additions & 7 deletions apps/ui/src/components/card/profileCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import {
Button,
type ButtonProps,
Flex,
Icon,
Menu,
MenuButton,
MenuItem,
MenuList,
Skeleton,
Text,
useClipboard,
useMediaQuery,
Expand All @@ -17,11 +19,10 @@ import { ExplorerTypes } from '../../types';
import { twitterLink } from '../../utils/formatter.ts';
import { getExplorer } from '../../utils/getExplorer';
import { MetadataKeys } from '../../utils/metadataKeys';
import { EditIcon, ExploreIcon, TwitterIcon } from '../icons';
import { AvatarIcon, EditIcon, ExploreIcon, TwitterIcon } from '../icons';
import { CopyIcon } from '../icons/copyIcon.tsx';
import { ShareIcon } from '../icons/shareicon.tsx';
import { useSidebar } from '../sidebar/hooks/useSidebar';
import { UserAvatar } from '../user/userAvatar.tsx';
import { useChainId } from '../../hooks/useChainId.ts';

interface IProfileCard {
Expand Down Expand Up @@ -205,11 +206,23 @@ export const ProfileCard = ({
zIndex={1}
>
<Flex w="full">
<UserAvatar
avatar={avatar?.value}
isAvatarLoading={isMetadataLoading}
/>

{avatar ? (
<Skeleton
isLoaded={!isMetadataLoading}
minW={32}
h={32}
rounded="lg"
mr={4}
bgImage={`url(${avatar.value})`}
bgSize="cover"
bgPosition="center"
bgRepeat="no-repeat"
border="1.5px solid"
borderColor={'button.500'}
/>
) : (
<Icon w={32} h={32} rounded="lg" mr={4} as={AvatarIcon} />
)}
<Flex
gap={4}
alignItems={isLowerThanMobile ? 'flex-start' : 'flex-start'}
Expand Down
14 changes: 12 additions & 2 deletions apps/ui/src/components/inputs/verifiedAccount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
InputLeftAddon,
type InputProps,
InputRightAddon,
Skeleton,
Text,
} from '@chakra-ui/react';
import type { ReactNode } from 'react';
Expand All @@ -29,6 +30,7 @@ interface CustomInputProps extends InputProps {
rightAddon: boolean;
rightAddonName: string | ReactNode;
variant: { key: MetadataKeys; value: string | undefined };
isMetadataLoading: boolean;
}

const VerifiedAccountInput = (props: CustomInputProps) => {
Expand Down Expand Up @@ -133,7 +135,15 @@ const VerifiedAccountInput = (props: CustomInputProps) => {

if (currentVariant) {
return (
<Box w="full" display="flex" alignItems="flex-end" flexDirection="column">
<Skeleton
w="full"
rounded="xl"
isLoaded={!props.isMetadataLoading}
h="fit-content"
display="flex"
alignItems="flex-end"
flexDirection="column"
>
<InputGroup>
<InputLeftAddon
bgColor={currentVariant?.bgColor}
Expand Down Expand Up @@ -246,7 +256,7 @@ const VerifiedAccountInput = (props: CustomInputProps) => {
Verify now
</Text>
)}
</Box>
</Skeleton>
);
}
};
Expand Down
2 changes: 1 addition & 1 deletion apps/ui/src/components/modal/transactionDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export const TransactionsDetailsModal = ({
justifyContent="start"
textColor="grey.100"
leftAction={'action'}
content="Registration"
content="Update profile"
/>
<Box w="full" display="flex" flexDirection="column" my={4}>
<Text
Expand Down
20 changes: 12 additions & 8 deletions apps/ui/src/components/sidebar/profile.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
Box,
Divider,
Flex,
FormControl,
Text,
useDisclosure,
Expand All @@ -20,13 +19,18 @@ import { DropdownAutocomplete } from '../inputs/dropdownAutocomplete';
import { useSidebar } from './hooks/useSidebar';
import { ENSBanner } from '../buttons/ensBanner';
import { NSDialog } from '../../modules/ens/components/dialog';
import { useMetadata } from '../../hooks/useMetadata';
import { MetadataKeys } from '@bako-id/sdk';

interface ProfileSidebarProps extends BoxProps {}

const ProfileSidebar = (props: ProfileSidebarProps) => {
const { metadata, loadingMetadata } = useMetadata();
const { isMyDomain } = useSidebar();
const [active, setActive] = useState<string>('');
const ensDialogState = useDisclosure();
const hasEns = !!metadata?.find((m) => m.key === MetadataKeys.ENS_DOMAIN);
const showEnsBanner = !hasEns && isMyDomain && !loadingMetadata;

return (
<>
Expand Down Expand Up @@ -89,23 +93,23 @@ const ProfileSidebar = (props: ProfileSidebarProps) => {
/>
</VStack>
<VStack spacing={4}>
{isMyDomain && (
{/* {isMyDomain && (
<Flex w="full" flexDirection="column" gap={2}>
{/* <SidebarBanner
<SidebarBanner
text="Click here to verify your X account and get benefits"
icon={TwitterBannerIcon}
/> */}
/>

{/* <SidebarBanner
<SidebarBanner
text="Click here to verify your Farcaster account and get benefits"
icon={FarcasterIcon}
bgColor="#7F5FC7"
iconColor="white"
/> */}
/>
</Flex>
)}
)} */}

<ENSBanner onClick={ensDialogState.onOpen} />
{showEnsBanner && <ENSBanner onClick={ensDialogState.onOpen} />}

<BakoSafeBanner
onClick={() => window.open('https://www.bako.global', '_blank')}
Expand Down
4 changes: 2 additions & 2 deletions apps/ui/src/hooks/useGetENSData.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useQuery } from '@tanstack/react-query';
import { ensCheckRegister } from '../modules/ens/services';
import { getEnsMetadata } from '../modules/ens/services';

const useGetENSData = (ensName: string) => {
const { data, ...rest } = useQuery({
queryKey: ['get-ens', ensName],
queryFn: async () => {
try {
const result = await ensCheckRegister(ensName);
const result = await getEnsMetadata(ensName);
if (!result) {
// Need to throw this error to activate the "retry" method.
throw new Error('Expected null value. Activating Retry method');
Expand Down
6 changes: 4 additions & 2 deletions apps/ui/src/hooks/useMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export type MetadataResponse =

export const useMetadata = (handleOnSuccess?: () => void) => {
const [updatedMetadata, setUpdatedMetadata] = useState<MetadataKeyValue[]>(
[],
[]
);
const { domain } = useParams({ strict: false });
const { provider } = useProvider();
Expand Down Expand Up @@ -64,6 +64,8 @@ export const useMetadata = (handleOnSuccess?: () => void) => {
},
enabled: !!domain,
refetchOnWindowFocus: false,
refetchOnMount: true,
staleTime: 1000 * 60 * 60 * 2,
});

const handleSaveRequest = useMutation({
Expand All @@ -75,7 +77,7 @@ export const useMetadata = (handleOnSuccess?: () => void) => {
...updatedMetadata.reduce(
// biome-ignore lint/performance/noAccumulatingSpread: <explanation>
(acc, { key, value }) => ({ ...acc, [key]: value }),
{},
{}
),
};

Expand Down
91 changes: 28 additions & 63 deletions apps/ui/src/modules/ens/services/ens.ts
Original file line number Diff line number Diff line change
@@ -1,77 +1,42 @@
import { MetadataKeys } from '@bako-id/sdk';
import { createEnsPublicClient } from '@ensdomains/ensjs';
import { http } from 'viem';
import { mainnet } from 'viem/chains';
import { type ENSMetadataKeys, ensToMetadataMap } from './types';

const { VITE_ENS_API_KEY } = import.meta.env;
import { ENSMetadataKeys, ensToMetadataMap } from './types';
import { ethers } from 'ethers';

const client = createEnsPublicClient({
chain: mainnet,
transport: http('https://web3.ens.domains/v1/mainnet'),
key: VITE_ENS_API_KEY,
});
const ethersProvider = new ethers.JsonRpcProvider(
'https://mainnet.infura.io/v3/a44094c3208b48f5bbdd76c7c83212fc'
);

const graphql_url = `https://gateway.thegraph.com/api/${VITE_ENS_API_KEY}/subgraphs/id/5XqPmWe6gjyrJtFn9cLy237i4cWw2j9HcUJEXsP5qGtH`;
export async function getEnsMetadata(name: string) {
const resolver = await ethersProvider.getResolver(name);

export const ensCheckRegister = async (name: string) => {
const records = await fetchEnsData(name);
if (!records) return null;

const keys = records.resolver.texts;

const request = await client.getRecords({
name,
texts: [...keys],
});

const mappedResult: Record<string, string> = {};

for (const { key, value } of request.texts) {
const ensKey = key as ENSMetadataKeys;
const metadataKey = ensToMetadataMap[ensKey];

if (metadataKey) {
mappedResult[metadataKey] = value;
try {
if (!resolver) {
return null;
}
}

mappedResult[MetadataKeys.ENS_DOMAIN] = name;
const metadata: Record<string, string> = {};

return mappedResult;
};
for (const key of Object.keys(ENSMetadataKeys)) {
const enumKey = key as keyof typeof ENSMetadataKeys;
const recordKey = ENSMetadataKeys[enumKey];
const metadataKey = ensToMetadataMap[recordKey];

async function fetchEnsData(name: string) {
const ensQuery = `query {
domains(
where: {
name: "${name}"
}
) {
name
expiryDate
registration {
expiryDate
registrationDate
}
resolver {
texts
contentHash
id

try {
const value = await resolver.getText(recordKey);
if (value) {
metadata[metadataKey] = value;
}
} catch (error) {
console.error(`Error fetching ${recordKey} for ${name}:`, error);
}
}
}`;
const response = await fetch(graphql_url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: ensQuery }),
});

const lklk = await response.json();
const d = lklk.data?.domains[0] ?? undefined;
metadata[MetadataKeys.ENS_DOMAIN] = name;

return d;
return metadata;
} catch (error) {
console.error(`Error fetching metadata for ${name}:`, error);
return null;
}
}
Loading