Login.res.mjs
1// Generated by ReScript, PLEASE EDIT WITH CARE
2
3import * as Fetch from "../ffi/Fetch.res.mjs";
4import * as State from "../State.res.mjs";
5import * as Preact from "../ffi/Preact.res.mjs";
6import * as Content from "./Content.res.mjs";
7import * as Core__JSON from "@rescript/core/lib/es6/src/Core__JSON.res.mjs";
8import * as Core__Option from "@rescript/core/lib/es6/src/Core__Option.res.mjs";
9import * as Signals from "@preact/signals";
10import * as JsxRuntime from "preact/jsx-runtime";
11
12let errors = Signals.signal(undefined);
13
14let signup = Signals.signal(false);
15
16let submitting = Signals.signal(false);
17
18function get(selector) {
19 let elem = document.querySelector(selector);
20 if (elem == null) {
21 return;
22 }
23 if (elem.value === undefined) {
24 return;
25 }
26 let v = elem.value;
27 if (!(v == null) && v !== "") {
28 return v;
29 }
30}
31
32function validateLoginForm(user, password) {
33 if (user !== undefined) {
34 if (password !== undefined) {
35 return "Valid";
36 } else {
37 return {
38 TAG: "Invalid",
39 _0: "Password is required"
40 };
41 }
42 } else if (password !== undefined) {
43 return {
44 TAG: "Invalid",
45 _0: "Username or handle is required"
46 };
47 } else {
48 return {
49 TAG: "Invalid",
50 _0: "Username and password are required"
51 };
52 }
53}
54
55function validateSignupForm(user, handle, password) {
56 if (user === undefined && handle === undefined) {
57 return {
58 TAG: "Invalid",
59 _0: "A handle or an email and a password are required"
60 };
61 }
62 if (password !== undefined) {
63 return "Valid";
64 } else {
65 return {
66 TAG: "Invalid",
67 _0: "A handle or an email and a password are required"
68 };
69 }
70}
71
72function parseUserFromJSON(json) {
73 let dict = Core__JSON.Decode.object(json);
74 if (dict === undefined) {
75 return;
76 }
77 let id = Core__Option.flatMap(dict["id"], Core__JSON.Decode.string);
78 let email = Core__Option.getOr(Core__Option.flatMap(dict["email"], Core__JSON.Decode.string), "");
79 let handle = Core__Option.getOr(Core__Option.flatMap(dict["handle"], Core__JSON.Decode.string), "");
80 let registered = Core__Option.getOr(Core__Option.flatMap(dict["registered"], Core__JSON.Decode.bool), false);
81 if (id !== undefined) {
82 return {
83 id: id,
84 email: email,
85 handle: handle,
86 registered: registered
87 };
88 }
89}
90
91async function submit() {
92 errors.value = undefined;
93 submitting.value = true;
94 let user = get("#user");
95 let pwd = get("#password");
96 let validation;
97 if (signup.value) {
98 let handle = get("#handle");
99 validation = validateSignupForm(user, handle, pwd);
100 } else {
101 validation = validateLoginForm(user, pwd);
102 }
103 if (typeof validation !== "object") {
104 let url = signup.value ? "/signup" : "/login";
105 let bodyDict = {};
106 bodyDict["user"] = Core__Option.getOr(user, "");
107 bodyDict["password"] = Core__Option.getOr(pwd, "");
108 if (signup.value) {
109 let handle$1 = get("#handle");
110 bodyDict["handle"] = Core__Option.getOr(handle$1, "");
111 }
112 await Fetch.send(Fetch.onResponse(Fetch.credentials(Fetch.setBody(Fetch.post(url), bodyDict), "include"), json => {
113 submitting.value = false;
114 let user = parseUserFromJSON(json);
115 if (user !== undefined) {
116 State.user.value = user;
117 State.content.value = undefined;
118 } else {
119 errors.value = "Invalid response from server";
120 }
121 }, (status, msg) => {
122 submitting.value = false;
123 errors.value = msg;
124 console.error("Login/signup failed", [
125 status,
126 msg
127 ]);
128 }));
129 return;
130 }
131 errors.value = validation._0;
132 submitting.value = false;
133}
134
135let fields = "bg-white border border-gray-300 text-gray-900 rounded-lg focus:ring-[var(--color-orange)] focus:border-[var(--color-orange)] block w-full p-2.5";
136
137function Login(props) {
138 let match = signup.value;
139 let match$1 = submitting.value;
140 let err = errors.value;
141 return JsxRuntime.jsxs("div", {
142 children: [
143 JsxRuntime.jsx(Content.CloseButton.make, {}),
144 JsxRuntime.jsxs("div", {
145 children: [
146 JsxRuntime.jsxs("div", {
147 children: [
148 JsxRuntime.jsx("label", {
149 children: signup.value ? "Email" : "Email or Handle",
150 className: Preact.cls("block text-sm font-medium", {
151 "mb-2": !signup.value
152 }),
153 htmlFor: "user"
154 }),
155 signup.value ? JsxRuntime.jsx("div", {
156 children: "Email is optional. Without it you can't reset your password.",
157 className: "text-xs text-gray-700 italic leading-none mb-2"
158 }) : null,
159 JsxRuntime.jsx("input", {
160 className: fields,
161 id: "user",
162 autoComplete: "off",
163 autoCapitalize: "off",
164 name: "user",
165 type: "text"
166 })
167 ],
168 className: ""
169 }),
170 signup.value ? JsxRuntime.jsxs("div", {
171 children: [
172 JsxRuntime.jsx("label", {
173 children: "Handle",
174 className: "block text-sm font-medium",
175 htmlFor: "handle"
176 }),
177 JsxRuntime.jsxs("div", {
178 children: [
179 JsxRuntime.jsx("span", {
180 children: "Your handle will appear on your public routes. You can change it later but it must be unique. Allowed characters:"
181 }),
182 JsxRuntime.jsx("span", {
183 children: " A-Z a-z 0-9 . _ @ - [] ! ",
184 className: "not-italic font-mono"
185 }),
186 JsxRuntime.jsx("span", {
187 children: "and at least 3 letters long."
188 })
189 ],
190 className: "text-xs text-gray-700 italic leading-none mb-2"
191 }),
192 JsxRuntime.jsx("input", {
193 className: fields,
194 id: "handle",
195 autoComplete: "off",
196 autoCapitalize: "off",
197 name: "handle"
198 })
199 ],
200 className: ""
201 }) : null,
202 JsxRuntime.jsxs("div", {
203 children: [
204 JsxRuntime.jsx("label", {
205 children: "Password",
206 className: "block mb-2 text-sm font-medium",
207 htmlFor: "password"
208 }),
209 JsxRuntime.jsx("input", {
210 className: fields,
211 id: "password",
212 autoComplete: "off",
213 autoCapitalize: "off",
214 name: "password",
215 type: "password"
216 })
217 ],
218 className: ""
219 }),
220 JsxRuntime.jsx("div", {
221 children: JsxRuntime.jsx("button", {
222 children: match ? (
223 match$1 ? "Submitting..." : "Sign up"
224 ) : (
225 match$1 ? "Submitting..." : "Login"
226 ),
227 className: "w-full text-white bg-[var(--color-orange)] focus:ring-4 focus:outline-none focus:ring-[var(--color-blue)] font-medium rounded-lg text-sm px-5 py-2.5 disabled:opacity-50 disabled:cursor-not-allowed",
228 disabled: submitting.value,
229 onClick: _evt => {
230 submit();
231 }
232 }),
233 className: ""
234 }),
235 err !== undefined ? JsxRuntime.jsx("div", {
236 children: err,
237 className: "bg-red-300 text-[var(--color-red)] px-4 py-2 rounded-sm"
238 }) : null,
239 signup.value ? JsxRuntime.jsxs("div", {
240 children: [
241 "Already have an account? ",
242 JsxRuntime.jsx("a", {
243 children: "Login",
244 className: "text-[var(--color-blue)] cursor-pointer underline decoration-dotted",
245 role: "button",
246 onClick: _evt => {
247 signup.value = false;
248 }
249 })
250 ],
251 className: ""
252 }) : JsxRuntime.jsxs("div", {
253 children: [
254 "Don't have an account? ",
255 JsxRuntime.jsx("a", {
256 children: "Sign up",
257 className: "text-[var(--color-blue)] cursor-pointer underline decoration-dotted",
258 role: "button",
259 onClick: _evt => {
260 signup.value = true;
261 }
262 })
263 ],
264 className: ""
265 })
266 ],
267 className: "space-y-4 md:space-y-6"
268 })
269 ],
270 className: "flex flex-col p-10 md:p-15"
271 });
272}
273
274let make = Login;
275
276export {
277 errors,
278 signup,
279 submitting,
280 get,
281 validateLoginForm,
282 validateSignupForm,
283 parseUserFromJSON,
284 submit,
285 fields,
286 make,
287}
288/* errors Not a pure module */