feature/share-libs
tsx 159 lines 5.41 KB
Raw
1 "use client";
2
3 import * as Form from "@radix-ui/react-form";
4 import { invoke } from "@tauri-apps/api/tauri";
5 import { TAURI_ACCOUNT_LOGIN } from "@/lib/tauri-handler";
6 import { useState } from "react";
7 import { UserContext } from "@/lib/current-user-context";
8 import { CurrentUser, CurrentUserType, db } from "@/lib/db";
9 import { AccountLoginResponse } from "@/models/account";
10 import { useRouter } from "next/navigation";
11 import { TauriResponse } from "@/models/shared";
12 import { Mode } from "@/models/mode";
13 import { LoadingView } from "@/components/ui/loading-view";
14 import { useLogger } from "@/lib/logger";
15 import { Button } from "@/components/button";
16
17 enum State {
18 LOADING,
19 LOADED,
20 ERROR,
21 }
22
23 export default function Page() {
24
25 const log = useLogger("Login/Page");
26 const router = useRouter();
27 const [state, setState] = useState(State.LOADED);
28 const [emailOrUsername, setEmailOrUsername] = useState("");
29 const [password, setPassword] = useState("");
30 const [errorMessage, setErrorMessage] = useState("");
31
32 const login = async (update: (user: CurrentUser) => void) => {
33 try {
34 setState(State.LOADING);
35 const payload = {
36 username: emailOrUsername,
37 password: password,
38 };
39 log.debug("payload", payload);
40 const response: AccountLoginResponse = await invoke(TAURI_ACCOUNT_LOGIN, payload);
41 log.debug("response", response);
42 if (response.status === TauriResponse.ERROR) {
43 console.error("Login failed", response);
44 setErrorMessage(response.message);
45 return;
46 }
47 // Sanity check
48 if (response.user === null || response.access_token === null) {
49 log.error("Login failed", response);
50 setErrorMessage(response.message);
51 return;
52 }
53
54 let currentUser: CurrentUser = {
55 accessToken: response.access_token,
56 type: CurrentUserType.MAIN,
57 user: response.user,
58 mode: Mode.Vocal
59 }
60 db.currentUser.add(currentUser)
61 // Update UserContext
62 update(currentUser);
63
64 router.push("/");
65 } catch (error) {
66 log.error("Login failed", error);
67 setErrorMessage("Login failed. Please try again.");
68 setState(State.ERROR);
69 }
70 };
71
72 if (state === State.LOADING) {
73 return <LoadingView />;
74 }
75
76 return (
77 <div className="prose prose-sm prose-invert max-w-none">
78 <div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
79 <UserContext.Consumer>
80 {({ user, updateUser: update }) => (
81 <Form.Root
82 className="FormRoot"
83 onSubmit={(event) => {
84 event.preventDefault();
85 }}
86 >
87 {state === State.ERROR && (
88 <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
89 <strong className="font-bold">Error!</strong>
90 <span className="block sm:inline">{errorMessage}</span>
91 </div>
92 )
93 }
94 <Form.Field className="FormField my-6" name="email">
95 <div
96 style={{
97 display: "flex",
98 alignItems: "baseline",
99 justifyContent: "space-between",
100 }}
101 >
102 <Form.Label className="FormLabel">Email</Form.Label>
103 <Form.Message className="FormMessage" match="valueMissing">
104 Please enter your email
105 </Form.Message>
106 <Form.Message className="FormMessage" match="typeMismatch">
107 Please provide a valid email
108 </Form.Message>
109 </div>
110 <Form.Control asChild>
111 <input
112 className="Input"
113 type="email"
114 value={emailOrUsername}
115 onChange={(e) => setEmailOrUsername(e.currentTarget.value)}
116 required
117 />
118 </Form.Control>
119 </Form.Field>
120 <Form.Field className="FormField my-6" name="password">
121 <div
122 style={{
123 display: "flex",
124 alignItems: "baseline",
125 justifyContent: "space-between",
126 }}
127 >
128 <Form.Label className="FormLabel">Password</Form.Label>
129 <Form.Message className="FormMessage" match="valueMissing">
130 Please enter your email
131 </Form.Message>
132 <Form.Message className="FormMessage" match="typeMismatch">
133 Please provide a valid email
134 </Form.Message>
135 </div>
136 <Form.Control asChild>
137 <input
138 className="Input"
139 type="password"
140 value={password}
141 onChange={(e) => {
142 setPassword(e.currentTarget.value);
143 }}
144 required
145 />
146 </Form.Control>
147 </Form.Field>
148 <Form.Field className="FormField my-6" name="password">
149 <Button onClick={() => login(update)} variant={"outline"} size={"lg"}>
150 Login
151 </Button>
152 </Form.Field>
153 </Form.Root>
154 )}
155 </UserContext.Consumer>
156 </div>
157 </div>
158 );
159 }