Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
1import { ERRORS } from "@hey/data/errors";
2import { useAuthenticateMutation, useChallengeMutation } from "@hey/indexer";
3import type { ApolloClientError } from "@hey/types/errors";
4import { useCallback, useState } from "react";
5import { toast } from "sonner";
6import { useAccount, useSignMessage } from "wagmi";
7import BackButton from "@/components/Shared/BackButton";
8import { Button, Card, CardHeader, H6 } from "@/components/Shared/UI";
9import errorToast from "@/helpers/errorToast";
10import useCopyToClipboard from "@/hooks/useCopyToClipboard";
11import useHandleWrongNetwork from "@/hooks/useHandleWrongNetwork";
12import { hydrateAuthTokens } from "@/store/persisted/useAuthStore";
13
14const Tokens = () => {
15 const { accessToken, refreshToken } = hydrateAuthTokens();
16 const [builderToken, setBuilderToken] = useState<string | null>(null);
17 const [isSubmitting, setIsSubmitting] = useState(false);
18
19 const copyAccessToken = useCopyToClipboard(
20 accessToken as string,
21 "Copied to clipboard"
22 );
23 const copyRefreshToken = useCopyToClipboard(
24 refreshToken as string,
25 "Copied to clipboard"
26 );
27 const copyBuilderToken = useCopyToClipboard(
28 builderToken ?? "",
29 "Copied to clipboard"
30 );
31
32 const { address } = useAccount();
33 const handleWrongNetwork = useHandleWrongNetwork();
34
35 const onError = useCallback((error: ApolloClientError) => {
36 setIsSubmitting(false);
37 errorToast(error);
38 }, []);
39
40 const { signMessageAsync } = useSignMessage({
41 mutation: { onError }
42 });
43 const [loadChallenge] = useChallengeMutation();
44 const [authenticate] = useAuthenticateMutation();
45
46 const handleGenerateBuilderToken = async () => {
47 try {
48 setIsSubmitting(true);
49 await handleWrongNetwork();
50
51 const challenge = await loadChallenge({
52 variables: { request: { builder: { address } } }
53 });
54
55 if (!challenge?.data?.challenge?.text) {
56 return toast.error(ERRORS.SomethingWentWrong);
57 }
58
59 // Get signature
60 const signature = await signMessageAsync({
61 message: challenge?.data?.challenge?.text
62 });
63
64 // Auth account
65 const auth = await authenticate({
66 variables: { request: { id: challenge.data.challenge.id, signature } }
67 });
68
69 if (auth.data?.authenticate.__typename === "AuthenticationTokens") {
70 setBuilderToken(auth.data?.authenticate.accessToken);
71 }
72 } catch (error) {
73 errorToast(error);
74 } finally {
75 setIsSubmitting(false);
76 }
77 };
78
79 return (
80 <Card>
81 <CardHeader
82 icon={<BackButton path="/settings" />}
83 title="Your temporary access token"
84 />
85 <div className="m-5 space-y-5">
86 <div className="flex flex-col gap-y-3">
87 <b>Your temporary access token</b>
88 <button
89 className="cursor-pointer break-all rounded-md bg-gray-300 p-2 px-3 text-left dark:bg-gray-600"
90 onClick={copyAccessToken}
91 type="button"
92 >
93 <H6>{accessToken}</H6>
94 </button>
95 </div>
96 <div className="flex flex-col gap-y-3">
97 <b>Your temporary refresh token</b>
98 <button
99 className="cursor-pointer break-all rounded-md bg-gray-300 p-2 px-3 text-left dark:bg-gray-600"
100 onClick={copyRefreshToken}
101 type="button"
102 >
103 <H6>{refreshToken}</H6>
104 </button>
105 </div>
106 <div className="flex flex-col gap-y-3">
107 <b>Your temporary builder token</b>
108 <Button
109 disabled={isSubmitting}
110 loading={isSubmitting}
111 onClick={handleGenerateBuilderToken}
112 >
113 Generate builder token
114 </Button>
115 {builderToken && (
116 <button
117 className="mt-5 cursor-pointer break-all rounded-md bg-gray-300 p-2 px-3 text-left dark:bg-gray-600"
118 onClick={copyBuilderToken}
119 type="button"
120 >
121 <H6>{builderToken}</H6>
122 </button>
123 )}
124 </div>
125 </div>
126 </Card>
127 );
128};
129
130export default Tokens;