AuthCodeForm.tsx raw
1 import { RefreshCwIcon } from "lucide-react";
2 import React, { useState } from "react";
3 import { useNavigate } from "react-router";
4 import Container from "src/components/Container";
5 import PasswordInput from "src/components/password/PasswordInput";
6 import TwoColumnLayoutHeader from "src/components/TwoColumnLayoutHeader";
7 import { Button } from "src/components/ui/button";
8 import { LoadingButton } from "src/components/ui/custom/loading-button";
9 import { Label } from "src/components/ui/label";
10 import { UnlinkAlbyAccount } from "src/components/UnlinkAlbyAccount";
11
12 import { useInfo } from "src/hooks/useInfo";
13 import { handleRequestError } from "src/utils/handleRequestError";
14 import { openLink } from "src/utils/openLink";
15 import { request } from "src/utils/request"; // build the project for this to appear
16
17 type AuthCodeFormProps = {
18 url: string;
19 };
20
21 function AuthCodeForm({ url }: AuthCodeFormProps) {
22 const [authCode, setAuthCode] = useState("");
23 const navigate = useNavigate();
24
25 const { data: info, mutate: refetchInfo } = useInfo();
26
27 const [hasRequestedCode, setRequestedCode] = React.useState(false);
28 const [isLoading, setLoading] = React.useState(false);
29
30 async function requestAuthCode() {
31 setRequestedCode((hasRequestedCode) => {
32 if (!url) {
33 return false;
34 }
35 if (!hasRequestedCode) {
36 openLink(url);
37 }
38 return true;
39 });
40 }
41
42 async function onSubmit(e: React.FormEvent) {
43 e.preventDefault();
44 setLoading(true);
45 try {
46 await request(`/api/alby/callback?code=${authCode}`, {
47 headers: {
48 "Content-Type": "application/json",
49 },
50 });
51 await refetchInfo();
52 navigate("/");
53 } catch (error) {
54 handleRequestError("Failed to connect", error);
55 }
56 setLoading(false);
57 }
58
59 return (
60 <Container>
61 <form onSubmit={onSubmit} className="flex flex-col items-center w-full">
62 <div className="grid gap-5">
63 <TwoColumnLayoutHeader
64 title="Connect your Alby Account"
65 pageTitle="Connect your Alby Account"
66 description="A new window will open. Sign in with your Alby Account, copy the Authorization Code, and paste it here."
67 />
68 {!hasRequestedCode && (
69 <>
70 <Button onClick={requestAuthCode}>
71 Request Authorization Code
72 </Button>
73 </>
74 )}
75 {hasRequestedCode && (
76 <>
77 <div className="grid gap-4 w-full">
78 <div className="grid gap-1.5">
79 <Label htmlFor="authorization-code">Authorization Code</Label>
80 <PasswordInput
81 autoFocus
82 id="authorization-code"
83 placeholder="Enter code you see in the browser"
84 onChange={setAuthCode}
85 value={authCode}
86 />
87 </div>
88 </div>
89 <div className="flex gap-4">
90 <LoadingButton loading={isLoading} className="flex-1">
91 Submit
92 </LoadingButton>
93 <Button
94 type="button"
95 size="icon"
96 variant="outline"
97 onClick={() => url && openLink(url)}
98 >
99 <RefreshCwIcon className="size-4" />
100 </Button>
101 </div>
102 </>
103 )}
104 {info?.albyUserIdentifier && (
105 <div className="flex flex-col justify-center items-center mt-15 gap-5">
106 <p className="text-muted-foreground">or</p>
107 <UnlinkAlbyAccount>
108 <Button variant="outline" size="sm">
109 Disconnect Alby Account
110 </Button>
111 </UnlinkAlbyAccount>
112 </div>
113 )}
114 </div>
115 </form>
116 </Container>
117 );
118 }
119
120 export default AuthCodeForm;
121