Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
1import { CheckCircleIcon } from "@heroicons/react/24/solid";
2import { ERRORS } from "@hey/data/errors";
3import {
4 ManagedAccountsVisibility,
5 useAccountsAvailableQuery,
6 useSwitchAccountMutation
7} from "@hey/indexer";
8import { useCallback, useState } from "react";
9import { useAccount } from "wagmi";
10import Loader from "@/components/Shared/Loader";
11import { ErrorMessage, Spinner, WarningMessage } from "@/components/Shared/UI";
12import cn from "@/helpers/cn";
13import errorToast from "@/helpers/errorToast";
14import reloadAllTabs from "@/helpers/reloadAllTabs";
15import { useAccountStore } from "@/store/persisted/useAccountStore";
16import { signIn } from "@/store/persisted/useAuthStore";
17import SmallSingleAccount from "./SmallSingleAccount";
18
19const SwitchAccounts = () => {
20 const { currentAccount } = useAccountStore();
21 const [isSubmitting, setIsSubmitting] = useState(false);
22 const [loggingInAccountId, setLoggingInAccountId] = useState<null | string>(
23 null
24 );
25 const { address } = useAccount();
26
27 const onError = useCallback((error?: unknown) => {
28 setIsSubmitting(false);
29 setLoggingInAccountId(null);
30 errorToast(error);
31 }, []);
32
33 const { data, error, loading } = useAccountsAvailableQuery({
34 skip: !address,
35 variables: {
36 accountsAvailableRequest: {
37 hiddenFilter: ManagedAccountsVisibility.NoneHidden,
38 managedBy: address
39 },
40 lastLoggedInAccountRequest: { address: address }
41 }
42 });
43 const [switchAccount] = useSwitchAccountMutation();
44
45 if (!address) {
46 return (
47 <WarningMessage
48 className="m-5"
49 message="Connect your wallet to switch accounts"
50 title="No wallet connected"
51 />
52 );
53 }
54
55 if (loading) {
56 return <Loader className="my-5" message="Loading Accounts" />;
57 }
58
59 const accountsAvailable = data?.accountsAvailable.items || [];
60
61 const handleSwitchAccount = async (account: string) => {
62 try {
63 setLoggingInAccountId(account);
64 setIsSubmitting(true);
65
66 const auth = await switchAccount({ variables: { request: { account } } });
67
68 if (auth.data?.switchAccount.__typename === "AuthenticationTokens") {
69 const accessToken = auth.data?.switchAccount.accessToken;
70 const refreshToken = auth.data?.switchAccount.refreshToken;
71 // Preserve theme and other local UI state by not signing out completely.
72 signIn({ accessToken, refreshToken });
73 reloadAllTabs();
74 return;
75 }
76
77 return onError({ message: ERRORS.SomethingWentWrong });
78 } catch {
79 onError();
80 }
81 };
82
83 return (
84 <div className="max-h-[80vh] overflow-y-auto p-2">
85 <ErrorMessage
86 className="m-2"
87 error={error}
88 title="Failed to load accounts"
89 />
90 {accountsAvailable.map((accountAvailable, index) => (
91 <button
92 className="flex w-full cursor-pointer items-center justify-between space-x-2 rounded-lg py-3 pr-4 pl-3 text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-800"
93 disabled={
94 currentAccount?.address === accountAvailable.account.address
95 }
96 key={accountAvailable?.account.address}
97 onClick={async () => {
98 const selectedAccount = accountsAvailable[index].account;
99 await handleSwitchAccount(selectedAccount.address);
100 }}
101 type="button"
102 >
103 <div
104 className={cn(
105 currentAccount?.address === accountAvailable.account.address &&
106 "font-bold"
107 )}
108 >
109 <SmallSingleAccount account={accountAvailable.account} />
110 </div>
111 {isSubmitting &&
112 accountAvailable.account.address === loggingInAccountId ? (
113 <Spinner size="xs" />
114 ) : currentAccount?.address === accountAvailable.account.address ? (
115 <CheckCircleIcon className="size-5 text-green-600" />
116 ) : null}
117 </button>
118 ))}
119 </div>
120 );
121};
122
123export default SwitchAccounts;