-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #43 from ankit-tailor/feat/indentity-component
Feat/indentity component
- Loading branch information
Showing
8 changed files
with
283 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
import { | ||
Avatar, | ||
Balance, | ||
Identity, | ||
Name, | ||
Social, | ||
} from "@composer-kit/ui/identity"; | ||
|
||
const meta: Meta<typeof Identity> = { | ||
component: Identity, | ||
argTypes: {}, | ||
}; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj<typeof Identity>; | ||
|
||
export const Primary: Story = { | ||
render: () => { | ||
return ( | ||
<Identity address="0x" className="flex gap-2 items-center" token="cUSD"> | ||
<Avatar /> | ||
<div className="flex flex-col"> | ||
<Name /> | ||
<Balance /> | ||
</div> | ||
<Social tag="twitter" /> | ||
</Identity> | ||
); | ||
}, | ||
name: "Indentity", | ||
args: {}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import React from "react"; | ||
import { useIdentity } from "./indentity"; | ||
|
||
function DefaultAvatar(): JSX.Element { | ||
return ( | ||
<svg | ||
fill="none" | ||
height="40" | ||
viewBox="0 0 40 40" | ||
width="40" | ||
xmlns="http://www.w3.org/2000/svg" | ||
> | ||
<path | ||
clipRule="evenodd" | ||
d="M5.00778 17.7143C3.16266 16.0662 2.0011 13.6687 2.0011 11C2.0011 6.02944 6.03054 2 11.0011 2C15.9717 2 20.0011 6.02944 20.0011 11C20.0011 13.6687 18.8395 16.0662 16.9944 17.7143C16.88 15.2738 15.3075 13.2145 13.1284 12.388C14.2534 11.6802 15.0011 10.4274 15.0011 9C15.0011 6.79086 13.2102 5 11.0011 5C8.79196 5 7.0011 6.79086 7.0011 9C7.0011 10.4274 7.74875 11.6802 8.87381 12.388C6.69469 13.2145 5.12219 15.2738 5.00778 17.7143ZM5.57936 20.5732C2.24834 18.6827 0.00109863 15.1038 0.00109863 11C0.00109863 4.92487 4.92597 0 11.0011 0C17.0762 0 22.0011 4.92487 22.0011 11C22.0011 15.1038 19.7539 18.6827 16.4228 20.5732C16.3637 20.6068 16.3042 20.6399 16.2444 20.6724C14.6857 21.5191 12.8996 22 11.0011 22C9.02974 22 7.1795 21.4814 5.57936 20.5732Z" | ||
fill="currentColor" | ||
fillRule="evenodd" | ||
/> | ||
</svg> | ||
); | ||
} | ||
|
||
export function Avatar(): JSX.Element { | ||
const { avatar, name: ensName } = useIdentity(); | ||
|
||
return ( | ||
<> | ||
{avatar ? ( | ||
<img | ||
alt={`${ensName}-avatar`} | ||
className="rounded-full h-10 w-10" | ||
src={avatar} | ||
/> | ||
) : ( | ||
<DefaultAvatar /> | ||
)} | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { useBalance } from "../core/internal/hooks/use-balance"; | ||
import { UTILITY_TOKENS } from "../core/internal/utils/constants"; | ||
import { cn } from "../utils/helper"; | ||
import { useIdentity } from "./indentity"; | ||
|
||
interface BalanceProps extends React.HTMLAttributes<HTMLParagraphElement> { | ||
precison?: number; | ||
} | ||
|
||
export function Balance({ | ||
className, | ||
precison = 3, | ||
...props | ||
}: BalanceProps): JSX.Element | null { | ||
const { address, token } = useIdentity(); | ||
const { balance } = useBalance({ | ||
address, | ||
tokenMetaData: UTILITY_TOKENS[token], | ||
}); | ||
|
||
return ( | ||
<p {...props} className={cn("text-sm", className)}> | ||
{`${parseFloat(balance).toFixed(precison)} ${token}`} | ||
</p> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { useState, useEffect } from "react"; | ||
import { mainnet } from "viem/chains"; | ||
import { normalize } from "viem/ens"; | ||
import { getPublicClient } from "../../core/internal/config/viem-public-client"; | ||
|
||
interface SocialProps { | ||
ensName: string; | ||
tag: "github" | "twitter" | "url" | "farcaster"; | ||
} | ||
|
||
const getSocialUrl = (tag: string, data: string) => { | ||
switch (tag) { | ||
case "github": | ||
return `https://github.com/${data}`; | ||
case "twitter": | ||
return `https://x.com/${data}`; | ||
case "url": | ||
return data; | ||
case "farcaster": | ||
return `https://warpcast.com/${data}`; | ||
default: | ||
return null; | ||
} | ||
}; | ||
|
||
export const useSocial = ({ ensName, tag }: SocialProps) => { | ||
const [socialData, setSocialData] = useState<{ | ||
tag: string; | ||
url: string | null; | ||
} | null>(null); | ||
|
||
useEffect(() => { | ||
const fetchSocialData = async () => { | ||
const client = getPublicClient(mainnet); | ||
|
||
const data = await client.getEnsText({ | ||
name: normalize(ensName), | ||
key: `com.${tag}`, | ||
}); | ||
|
||
if (data) { | ||
setSocialData({ | ||
url: getSocialUrl(tag, data), | ||
tag, | ||
}); | ||
} else { | ||
setSocialData(null); | ||
} | ||
}; | ||
|
||
fetchSocialData(); | ||
}, [ensName]); | ||
|
||
return socialData; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import React, { | ||
createContext, | ||
useContext, | ||
useMemo, | ||
type HTMLAttributes, | ||
} from "react"; | ||
import { type Address } from "viem"; | ||
import { mainnet } from "viem/chains"; | ||
import { useEnsAvatar, useEnsName } from "wagmi"; | ||
|
||
interface IdentityProps extends HTMLAttributes<HTMLDivElement> { | ||
address: Address; | ||
token?: "CELO" | "cUSD" | "USDT"; | ||
} | ||
|
||
interface IdentityContextType { | ||
address: Address; | ||
name: string; | ||
avatar: string; | ||
balance: string; | ||
token: "CELO" | "cUSD" | "USDT"; | ||
} | ||
|
||
const IdentityContext = createContext<IdentityContextType | null>(null); | ||
|
||
export function Identity({ | ||
children, | ||
token = "CELO", | ||
address, | ||
...props | ||
}: IdentityProps): JSX.Element { | ||
const { data: ensName, isLoading: isEnsLoading } = useEnsName({ | ||
address, | ||
chainId: mainnet.id, | ||
query: { | ||
enabled: true, | ||
}, | ||
}); | ||
const { data: avatar, isLoading: isAvatarLoading } = useEnsAvatar({ | ||
name: ensName ?? "", | ||
chainId: mainnet.id, | ||
}); | ||
|
||
const contextValue = useMemo(() => { | ||
return { | ||
address, | ||
name: ensName ?? "", | ||
avatar: avatar ?? "", | ||
balance: "0", | ||
token, | ||
}; | ||
}, [address, avatar, ensName, token]); | ||
|
||
if (isEnsLoading || isAvatarLoading) { | ||
return <div />; | ||
} | ||
|
||
return ( | ||
<IdentityContext.Provider value={contextValue}> | ||
<div {...props}> {children}</div> | ||
</IdentityContext.Provider> | ||
); | ||
} | ||
|
||
export const useIdentity = (): IdentityContextType => { | ||
const context = useContext(IdentityContext); | ||
|
||
if (!context) { | ||
throw new Error("useIdentity must be used within an IdentityProvider"); | ||
} | ||
|
||
return context; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export { Identity } from "./indentity"; | ||
export { Avatar } from "./avatar"; | ||
export { Name } from "./name"; | ||
export { Balance } from "./balance"; | ||
export { Social } from "./social"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { cn } from "../utils/helper"; | ||
import { useIdentity } from "./indentity"; | ||
|
||
interface NameProps extends React.HTMLAttributes<HTMLParagraphElement> { | ||
isTruncated?: boolean; | ||
} | ||
|
||
const getTruncatedAddress = (address: string): string => { | ||
return `${address.slice(0, 6)}...${address.slice(-4)}`; | ||
}; | ||
|
||
export function Name({ | ||
isTruncated = true, | ||
className, | ||
...props | ||
}: NameProps): JSX.Element | null { | ||
const { address, name } = useIdentity(); | ||
|
||
return ( | ||
<p {...props} className={cn("font-bold text-base", className)}> | ||
{name || isTruncated ? getTruncatedAddress(address) : address} | ||
</p> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { useSocial } from "./hooks/use-social"; | ||
import { useIdentity } from "./indentity"; | ||
|
||
interface SocialProps extends React.HTMLAttributes<HTMLAnchorElement> { | ||
tag: "github" | "twitter" | "url" | "farcaster"; | ||
} | ||
|
||
export function Social({ | ||
className, | ||
tag, | ||
children, | ||
...props | ||
}: SocialProps): JSX.Element | null { | ||
const { name } = useIdentity(); | ||
const data = useSocial({ | ||
ensName: name, | ||
tag, | ||
}); | ||
|
||
if (!data) return null; | ||
|
||
return ( | ||
<a href={data?.url ?? "#"} target="_blank" className={className} {...props}> | ||
{children ?? tag} | ||
</a> | ||
); | ||
} |