Skip to content

Commit

Permalink
🌺 Lens and Hey v3: v29 (#lens-v3)
Browse files Browse the repository at this point in the history
Summary: Migrated to Lens v3, updating username handling and transaction processes.

Highlights:

• Replaced `username?.value` with `username?.localName` across components for username handling.
• Introduced `useUsernamesQuery` and `useAssignUsernameToAccountMutation` for username management.
• Added optimistic transaction handling for block/unblock and username assignment.

Read more: https://pierre.co/hey/hey/lens-v3
  • Loading branch information
Yoginth authored and Pierre committed Dec 6, 2024
1 parent 9ae4554 commit ebbe5f4
Show file tree
Hide file tree
Showing 22 changed files with 488 additions and 245 deletions.
10 changes: 8 additions & 2 deletions apps/web/src/components/Notification/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ export const NotificationAccountAvatar: FC<NotificationProfileProps> = ({
};

return (
<AccountPreview handle={account.username?.value} address={account.address}>
<AccountPreview
handle={account.username?.localName}
address={account.address}
>
<Link
className="rounded-full outline-offset-2"
href={getAccount(account).link}
Expand All @@ -48,7 +51,10 @@ export const NotificationAccountName: FC<NotificationProfileProps> = ({
const profileLink = getAccount(account).link;

return (
<AccountPreview handle={account.username?.value} address={account.address}>
<AccountPreview
handle={account.username?.localName}
address={account.address}
>
<Link
className="inline-flex items-center space-x-1 font-bold outline-none hover:underline focus:underline"
href={profileLink}
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/Post/PostAccount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const PostAccount: FC<PostAccountProps> = ({
href={getAccount(account).link}
>
<AccountPreview
handle={account.username?.value}
handle={account.username?.localName}
address={account.address}
showUserPreview
>
Expand Down
132 changes: 93 additions & 39 deletions apps/web/src/components/Settings/Handles/LinkHandle.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,97 @@
import IndexStatus from "@components/Shared/IndexStatus";
import LazySmallSingleAccount from "@components/Shared/LazySmallSingleAccount";
import Loader from "@components/Shared/Loader";
import Slug from "@components/Shared/Slug";
import errorToast from "@helpers/errorToast";
import { AtSymbolIcon } from "@heroicons/react/24/outline";
import { Errors } from "@hey/data/errors";
import selfFundedTransactionData from "@hey/helpers/selfFundedTransactionData";
import sponsoredTransactionData from "@hey/helpers/sponsoredTransactionData";
import {
useAssignUsernameToAccountMutation,
useUsernamesQuery
} from "@hey/indexer";
import { OptmisticPostType } from "@hey/types/enums";
import type { OptimisticTransaction } from "@hey/types/misc";
import { Button, EmptyState } from "@hey/ui";
import type { FC } from "react";
import { useState } from "react";
import toast from "react-hot-toast";
import { useAccountStatus } from "src/store/non-persisted/useAccountStatus";
import { useAccountStore } from "src/store/persisted/useAccountStore";
import { useTransactionStore } from "src/store/persisted/useTransactionStore";
import { sendEip712Transaction, sendTransaction } from "viem/zksync";
import { useWalletClient } from "wagmi";

const LinkHandle: FC = () => {
const { currentAccount } = useAccountStore();
const { isSuspended } = useAccountStatus();
const [linkingHandle, setLinkingHandle] = useState<null | string>(null);
const { addTransaction } = useTransactionStore();

const onError = (error: any) => {
setLinkingHandle(null);
errorToast(error);
const [linkingUsername, setLinkingUsername] = useState<null | string>(null);
const { data: walletClient } = useWalletClient();

const generateOptimisticAssignUsername = ({
txHash
}: {
txHash: string;
}): OptimisticTransaction => {
return {
txHash,
type: OptmisticPostType.AssignUsername
};
};

const onCompleted = (hash: string) => {
setLinkingUsername(null);
addTransaction(generateOptimisticAssignUsername({ txHash: hash }));
toast.success("Linked");
};

const { data, loading } = useOwnedHandlesQuery({
variables: { request: { for: currentAccount?.owner } }
const { data, loading } = useUsernamesQuery({
variables: { request: { owner: currentAccount?.owner } }
});

const [assignUsernameToAccount] = useAssignUsernameToAccountMutation({
onCompleted: async ({ assignUsernameToAccount }) => {
if (assignUsernameToAccount.__typename === "AssignUsernameResponse") {
return onCompleted(assignUsernameToAccount.hash);
}

if (walletClient) {
if (
assignUsernameToAccount.__typename === "SponsoredTransactionRequest"
) {
const hash = await sendEip712Transaction(walletClient, {
account: walletClient.account,
...sponsoredTransactionData(assignUsernameToAccount.raw)
});

return onCompleted(hash);
}

if (
assignUsernameToAccount.__typename === "SelfFundedTransactionRequest"
) {
const hash = await sendTransaction(walletClient, {
account: walletClient.account,
...selfFundedTransactionData(assignUsernameToAccount.raw)
});

return onCompleted(hash);
}
}

if (assignUsernameToAccount.__typename === "TransactionWillFail") {
return toast.error(assignUsernameToAccount.reason);
}
},
onError: (error) => {
setLinkingUsername(null);
errorToast(error);
}
});

const handleLink = async (handle: string) => {
const handleLink = async (username: string) => {
if (!currentAccount) {
return;
}
Expand All @@ -41,66 +106,55 @@ const LinkHandle: FC = () => {
return;
}

try {
setLinkingHandle(handle);
const request: LinkHandleToProfileRequest = { handle };
setLinkingUsername(username);

return await createLinkHandleToProfileTypedData({
variables: { request }
});
} catch (error) {
onError(error);
}
return await assignUsernameToAccount({
variables: { request: { username: { localName: username } } }
});
};

if (loading) {
return <Loader className="py-10" />;
}

const ownedHandles = data?.ownedHandles.items.filter(
(handle) => handle.linkedTo?.nftTokenId !== currentAccount?.address
const availableUsernames = data?.usernames.items.filter(
(handle) => handle.linkedTo !== currentAccount?.address
);

if (!ownedHandles?.length) {
if (!availableUsernames?.length) {
return (
<EmptyState
hideCard
icon={<AtSymbolIcon className="size-8" />}
message="No handles found to link!"
message="No usernames found to link!"
/>
);
}

return (
<div className="m-5 space-y-6">
{ownedHandles?.map((handle) => (
{availableUsernames?.map((username) => (
<div
className="flex flex-wrap items-center justify-between gap-3"
key={handle.fullHandle}
key={username.value}
>
<div className="flex items-center space-x-2">
<Slug className="font-bold" slug={handle.fullHandle} />
{handle.linkedTo ? (
<Slug className="font-bold" slug={username.value} />
{username.linkedTo ? (
<div className="flex items-center space-x-2">
<span>·</span>
<div>Linked to</div>
<LazySmallSingleAccount address={handle.linkedTo?.nftTokenId} />
<LazySmallSingleAccount address={username.linkedTo} />
</div>
) : null}
</div>
{writeHash ? (
<div className="mt-2">
<IndexStatus shouldReload txHash={writeHash} />
</div>
) : (
<Button
disabled={linkingHandle === handle.fullHandle}
onClick={() => handleLink(handle.fullHandle)}
outline
>
{handle.linkedTo ? "Unlink and Link" : "Link"}
</Button>
)}
<Button
disabled={linkingUsername === username.value}
onClick={() => handleLink(username.value)}
outline
>
{username.linkedTo ? "Unlink and Link" : "Link"}
</Button>
</div>
))}
</div>
Expand Down
102 changes: 76 additions & 26 deletions apps/web/src/components/Settings/Handles/UnlinkHandle.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,88 @@
import IndexStatus from "@components/Shared/IndexStatus";
import errorToast from "@helpers/errorToast";
import { Errors } from "@hey/data/errors";
import selfFundedTransactionData from "@hey/helpers/selfFundedTransactionData";
import sponsoredTransactionData from "@hey/helpers/sponsoredTransactionData";
import { useUnassignUsernameFromAccountMutation } from "@hey/indexer";
import { OptmisticPostType } from "@hey/types/enums";
import type { OptimisticTransaction } from "@hey/types/misc";
import { Button } from "@hey/ui";
import type { FC } from "react";
import { useState } from "react";
import toast from "react-hot-toast";
import { useAccountStatus } from "src/store/non-persisted/useAccountStatus";
import { useAccountStore } from "src/store/persisted/useAccountStore";
import { useTransactionStore } from "src/store/persisted/useTransactionStore";
import { sendEip712Transaction, sendTransaction } from "viem/zksync";
import { useWalletClient } from "wagmi";

const UnlinkHandle: FC = () => {
const { currentAccount } = useAccountStore();
const { isSuspended } = useAccountStatus();
const { addTransaction } = useTransactionStore();
const [unlinking, setUnlinking] = useState<boolean>(false);
const { data: walletClient } = useWalletClient();

const onError = (error: any) => {
const generateOptimisticUnassignUsername = ({
txHash
}: {
txHash: string;
}): OptimisticTransaction => {
return {
txHash,
type: OptmisticPostType.UnassignUsername
};
};

const onCompleted = (hash: string) => {
setUnlinking(false);
errorToast(error);
addTransaction(generateOptimisticUnassignUsername({ txHash: hash }));
toast.success("Unlinked");
};

const [unassignUsernameFromAccount] = useUnassignUsernameFromAccountMutation({
onCompleted: async ({ unassignUsernameFromAccount }) => {
if (
unassignUsernameFromAccount.__typename === "UnassignUsernameResponse"
) {
return onCompleted(unassignUsernameFromAccount.hash);
}

if (walletClient) {
if (
unassignUsernameFromAccount.__typename ===
"SponsoredTransactionRequest"
) {
const hash = await sendEip712Transaction(walletClient, {
account: walletClient.account,
...sponsoredTransactionData(unassignUsernameFromAccount.raw)
});

return onCompleted(hash);
}

if (
unassignUsernameFromAccount.__typename ===
"SelfFundedTransactionRequest"
) {
const hash = await sendTransaction(walletClient, {
account: walletClient.account,
...selfFundedTransactionData(unassignUsernameFromAccount.raw)
});

return onCompleted(hash);
}
}

if (unassignUsernameFromAccount.__typename === "TransactionWillFail") {
return toast.error(unassignUsernameFromAccount.reason);
}
},
onError: (error) => {
setUnlinking(false);
errorToast(error);
}
});

const handleUnlink = async () => {
if (!currentAccount) {
return;
Expand All @@ -27,32 +92,17 @@ const UnlinkHandle: FC = () => {
return toast.error(Errors.Suspended);
}

try {
setUnlinking(true);
const request: UnlinkHandleFromProfileRequest = {
handle: currentAccount.username?.value
};

return await createUnlinkHandleFromProfileTypedData({
variables: { request }
});
} catch (error) {
onError(error);
}
setUnlinking(true);

return await unassignUsernameFromAccount({
variables: { request: currentAccount.address }
});
};

return (
<div className="m-5">
{writeHash ? (
<div className="mt-2">
<IndexStatus shouldReload txHash={writeHash} />
</div>
) : (
<Button disabled={unlinking} onClick={handleUnlink} outline>
Un-link handle
</Button>
)}
</div>
<Button className="m-5" disabled={unlinking} onClick={handleUnlink} outline>
Un-link handle
</Button>
);
};

Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/Settings/Handles/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const HandlesSettings: NextPage = () => {
is no longer publicly displayed or associated with your profile."
title={
<span>
Unlink <Slug slug={currentAccount.username?.value} /> from
Unlink <Slug slug={currentAccount.username?.localName} /> from
your profile
</span>
}
Expand Down
Loading

0 comments on commit ebbe5f4

Please sign in to comment.