-
Notifications
You must be signed in to change notification settings - Fork 246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: new OnchainName component #49
Conversation
README.md
Outdated
@@ -213,6 +213,29 @@ type FrameMetadataResponse = { | |||
<br /> | |||
<br /> | |||
|
|||
## OnchainName 📛 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This new section will be called Identity Kit, which will have a callection of components and utilities around Onchain Identity.
<OnchainName address="0x1234567890abcdef1234567890abcdef12345678" sliced={false} />; | ||
``` | ||
|
||
**@Param** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I think we can use types going forward to better describe what's going on. Check the latest README.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
soon we might have autogen docs that will be based on type correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe... There is a difference between type
information, and how to teach how to use something.
Vitepress will automate docs creation in some capacity, but the ART of teaching how to use a function is still a manual work.
src/components/OnchainName.tsx
Outdated
import type { Address } from 'viem'; | ||
|
||
type OnchainNameProps = { | ||
address?: Address; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the address
should be mandatory
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If OnchainName
accepts undefined address
import { useAccount } from 'wagmi';
import { OnchainName } from '@/components/OnchainName';
function App() {
// may be undefined
const { address } = useAccount();
// Will return empty span if address is undefined
return <OnchainName address={address} />
}
If OnchainName
rejects undefined address
import { useAccount } from 'wagmi';
import { OnchainName } from '@/components/OnchainName';
function App() {
// may be undefined
const { address } = useAccount();
if (!address) {
return null;
}
// Will cause type error if we do not check address first
return <OnchainName address={address} />
}
Looking at likely example use case, it feels less cumbersome to allow address
to be undefined. Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed with @cnasc. vote to accept to make less cumbersome for consumers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You just made my point, you allow user to shot themself if the address is not there. And than they end up in a broken state.
vote to accept to make less cumbersome for consumers.
The consumer will see an empty name, that's not a good experience.
@cnasc @alvaroraminelli what am I missing? If you want an OnchainName, you need a an address. Simple. Why are we allowing folks to say, I have not an address today. It's a bit saying, I go to a coffee shop I ask for coffee, I don't have money, and still expect an empty cup of coffee because I have no money. Well if you don't have money I want someone to tell me, sorry no coffee until you have money.
Right?
src/components/OnchainName.tsx
Outdated
export function OnchainName({ address, className, sliced = true, props }: OnchainNameProps) { | ||
const { ensName } = useEnsName(address); | ||
|
||
const normilizedAddress = useMemo(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment here why we have useMemo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also should we avoid have CPU execution for the normilizedAddress
if in case of ensName we will use that anyway?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const normilizedAddress = useMemo(() => { | |
const normalizedAddress = useMemo(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I think the idea here is that the input address will display until ens name resolves. I don't think that's unreasonable, but maybe we'd prefer an explicit loading state?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great call. Yes, we need loading state here. Wondering how the UX would look like when you have a list of users in the UX, will things shift and change like crazy. User might opt-in to display loading state.
Need some UX thinking here.
src/store/client.ts
Outdated
import { createPublicClient, http } from 'viem'; | ||
import { mainnet } from 'viem/chains'; | ||
|
||
export const publicClient: ReturnType<typeof createPublicClient> = createPublicClient({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think client
should go in src/network
or more a location where we handle Data Layer stuff. cc @robpolak
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
src/store/inMemoryStorageService.ts
Outdated
|
||
// InMemoryStorageService: A service to store data in JavaScript memory. | ||
// It's a simple key-value storage using a Map. The data is stored as long as the page is not reloaded. | ||
export class InMemoryStorageService implements StorageInterface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's convert this to functional at some point. Let's keep OnchainKit class free.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we see this as a frontend-only use case? If so, it might be best to expose this as a context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see this evolving towards sharing in context as well. We might want build a light version of react-query for actions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see this evolving towards sharing in context as well.
React Context are a slippery slop, where folks think everything should be a context. Library should have like 90% of their state being just variable shared between functions. And for very very small exential stuff you can have Context that optimizes the Hooks story.
So before we build any React Context, it's important to ask the question, on where is the benefit for the end application. If it's just a nice to have for us as developer, than we don't need that. But again, for Hooks Rendering optimization, that we can talk about it.
Before we merge, let's have also a quick review from @cnasc, @robpolak, @wespickett and @Sneh1999 on this epic first Identity component. |
src/components/OnchainName.test.tsx
Outdated
it('displays sliced address when ENS name is not available and sliced is true as default', () => { | ||
(useEnsName as jest.Mock).mockReturnValue({ ensName: null }); | ||
(getSlicedAddress as jest.Mock).mockImplementation( | ||
(addr) => addr.slice(0, 6) + '...' + addr.slice(-4), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be mocked? I notice that the implementation here is slightly different from the one in the real function. Is that significant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tried the approach below but it is not working. fallback to mocking the entire function.
import * as addressUtils from '../core/address';
beforeEach(() => {
jest.clearAllMocks();
jest.spyOn(addressUtils, 'getSlicedAddress');
});
expect(addressUtils.getSlicedAddress).toHaveBeenCalledTimes(0);
lgtm. We ended up switching to extend the next/jest config in build-onchain-apps, but if tests run successfully as is, then it should be fine with the current config https://github.com/coinbase/build-onchain-apps/blob/main/template/jest.config.js#L1 |
}, [address, isLoading]); | ||
|
||
if (isLoading) { | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not for later, this will cause a Layout Shift. Something to consider in follow up PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BRILLIANT
What changed? Why?
Adding the first
OnchainName
component of our Identity Kit 👤The
OnchainName
component primarily focuses on showcasing ENS names for given Ethereum addresses, and defaults to displaying a sliced version of the address when an ENS name isn't available.Notes to reviewers
How has it been tested?