Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
1import { AtSymbolIcon } from "@heroicons/react/24/outline";
2import {
3 useAssignUsernameToAccountMutation,
4 useUsernamesQuery
5} from "@hey/indexer";
6import type { ApolloClientError } from "@hey/types/errors";
7import { useCallback, useState } from "react";
8import { toast } from "sonner";
9import LazySmallSingleAccount from "@/components/Shared/Account/LazySmallSingleAccount";
10import Loader from "@/components/Shared/Loader";
11import Slug from "@/components/Shared/Slug";
12import { Button, EmptyState, H6 } from "@/components/Shared/UI";
13import errorToast from "@/helpers/errorToast";
14import useTransactionLifecycle from "@/hooks/useTransactionLifecycle";
15import { useAccountStore } from "@/store/persisted/useAccountStore";
16
17const LinkUsername = () => {
18 const { currentAccount } = useAccountStore();
19 const [linkingUsername, setLinkingUsername] = useState<null | string>(null);
20 const handleTransactionLifecycle = useTransactionLifecycle();
21
22 const onCompleted = () => {
23 setLinkingUsername(null);
24 toast.success("Linked");
25 };
26
27 const onError = useCallback((error: ApolloClientError) => {
28 setLinkingUsername(null);
29 errorToast(error);
30 }, []);
31
32 const { data, loading } = useUsernamesQuery({
33 variables: {
34 request: {
35 filter: {
36 namespace: "0x1aA55B9042f08f45825dC4b651B64c9F98Af4615",
37 owner: currentAccount?.address
38 }
39 }
40 }
41 });
42
43 const [assignUsernameToAccount] = useAssignUsernameToAccountMutation({
44 onCompleted: async ({ assignUsernameToAccount }) => {
45 if (assignUsernameToAccount.__typename === "AssignUsernameResponse") {
46 return onCompleted();
47 }
48
49 return await handleTransactionLifecycle({
50 onCompleted,
51 onError,
52 transactionData: assignUsernameToAccount
53 });
54 },
55 onError
56 });
57
58 const handleLink = async (localName: string) => {
59 if (!currentAccount) {
60 return;
61 }
62
63 const confirmation = confirm(
64 "Are you sure you want to link this username to your account?"
65 );
66
67 if (!confirmation) {
68 return;
69 }
70
71 setLinkingUsername(localName);
72
73 return await assignUsernameToAccount({
74 variables: { request: { username: { localName } } }
75 });
76 };
77
78 if (loading) {
79 return <Loader className="my-10" />;
80 }
81
82 const usernames = data?.usernames.items;
83
84 if (!usernames?.length) {
85 return (
86 <EmptyState
87 hideCard
88 icon={<AtSymbolIcon className="size-8" />}
89 message="No usernames found to link!"
90 />
91 );
92 }
93
94 return (
95 <div className="m-5 flex flex-col gap-y-5">
96 <div className="flex flex-col gap-y-1.5">
97 <b>Link a username</b>
98 <H6 className="font-normal text-gray-500 dark:text-gray-200">
99 Link a username to your account to showcase it publicly, allowing
100 others to easily identify and connect with you based on your unique
101 online identity.
102 </H6>
103 </div>
104 {usernames?.map((username) => (
105 <div
106 className="flex flex-wrap items-center justify-between gap-3"
107 key={username.value}
108 >
109 <div className="flex items-center space-x-2">
110 <Slug className="font-bold" slug={username.value} />
111 {username.linkedTo ? (
112 <div className="flex items-center space-x-2">
113 <span>路</span>
114 <div>Linked to</div>
115 <LazySmallSingleAccount address={username.linkedTo} />
116 </div>
117 ) : null}
118 </div>
119 {username.linkedTo ? null : (
120 <Button
121 disabled={linkingUsername === username.localName}
122 loading={linkingUsername === username.localName}
123 onClick={() => handleLink(username.localName)}
124 outline
125 >
126 Link
127 </Button>
128 )}
129 </div>
130 ))}
131 </div>
132 );
133};
134
135export default LinkUsername;