@authdog/react-elements 0.0.39 → 0.0.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/.turbo/turbo-build.log +29 -26
  2. package/CHANGELOG.md +6 -0
  3. package/dist/components/ui/alert.js.map +1 -1
  4. package/dist/components/ui/alert.mjs.map +1 -1
  5. package/dist/components/ui/avatar.js.map +1 -1
  6. package/dist/components/ui/avatar.mjs.map +1 -1
  7. package/dist/components/ui/badge.js.map +1 -1
  8. package/dist/components/ui/badge.mjs.map +1 -1
  9. package/dist/components/ui/card.js.map +1 -1
  10. package/dist/components/ui/card.mjs.map +1 -1
  11. package/dist/components/ui/dropdown-menu.js.map +1 -1
  12. package/dist/components/ui/dropdown-menu.mjs.map +1 -1
  13. package/dist/components/ui/input.js.map +1 -1
  14. package/dist/components/ui/input.mjs.map +1 -1
  15. package/dist/components/ui/label.js.map +1 -1
  16. package/dist/components/ui/label.mjs.map +1 -1
  17. package/dist/components/ui/separator.js.map +1 -1
  18. package/dist/components/ui/separator.mjs.map +1 -1
  19. package/dist/components/ui/sheet.js.map +1 -1
  20. package/dist/components/ui/sheet.mjs.map +1 -1
  21. package/dist/index.d.mts +1 -1
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.mjs.map +1 -1
  25. package/dist/styles.css +1 -1
  26. package/package.json +5 -5
  27. package/src/components/core/client-only.tsx +10 -15
  28. package/src/components/core/navbar.tsx +81 -50
  29. package/src/components/core/placeholder-alert.tsx +7 -9
  30. package/src/components/core/user-dropdown.tsx +97 -55
  31. package/src/components/core/user-profile.tsx +180 -86
  32. package/src/components/flow/login.tsx +42 -29
  33. package/src/components/flow/totp-validator.tsx +94 -73
  34. package/src/components/icons.tsx +13 -13
  35. package/src/components/ui/alert.tsx +11 -11
  36. package/src/components/ui/avatar.tsx +10 -10
  37. package/src/components/ui/badge.tsx +9 -9
  38. package/src/components/ui/card.tsx +13 -13
  39. package/src/components/ui/dropdown-menu.tsx +39 -37
  40. package/src/components/ui/input.tsx +5 -5
  41. package/src/components/ui/label.tsx +7 -7
  42. package/src/components/ui/separator.tsx +7 -7
  43. package/src/components/ui/sheet.tsx +21 -21
  44. package/src/index.ts +6 -6
  45. package/src/main.tsx +4 -6
  46. package/src/preview.tsx +4 -8
  47. package/src/stories/Button._stories.tsx +15 -11
  48. package/src/stories/LoginForm.stories.tsx +6 -6
  49. package/src/stories/Navbar._stories.tsx +57 -19
  50. package/src/stories/PlaceholderAlert._stories.tsx +8 -8
  51. package/src/stories/TotpValidator.stories.tsx +10 -8
  52. package/src/stories/UserDropdown.stories.tsx +7 -9
  53. package/src/stories/UserProfile.stories.tsx +12 -12
  54. package/tsup.config.ts +6 -9
@@ -1,9 +1,13 @@
1
- "use client"
1
+ "use client";
2
2
 
3
- import { useEffect, useState } from "react"
4
- import { Avatar, AvatarFallback, AvatarImage } from "../../components/ui/avatar"
5
- import { Button } from "../../components/ui/button"
6
- import { Badge } from "../../components/ui/badge"
3
+ import { useEffect, useState } from "react";
4
+ import {
5
+ Avatar,
6
+ AvatarFallback,
7
+ AvatarImage,
8
+ } from "../../components/ui/avatar";
9
+ import { Button } from "../../components/ui/button";
10
+ import { Badge } from "../../components/ui/badge";
7
11
  import {
8
12
  Card,
9
13
  CardHeader,
@@ -11,19 +15,26 @@ import {
11
15
  CardDescription,
12
16
  CardContent,
13
17
  CardFooter,
14
- } from "../../components/ui/card"
15
- import { Input } from "../../components/ui/input"
16
- import { Label } from "../../components/ui/label"
17
- import { User, Shield, SlidersHorizontal, LucideProps } from "lucide-react"
18
+ } from "../../components/ui/card";
19
+ import { Input } from "../../components/ui/input";
20
+ import { Label } from "../../components/ui/label";
21
+ import { User, Shield, SlidersHorizontal, LucideProps } from "lucide-react";
18
22
 
19
23
  export interface UserProfileProps {
20
24
  loading: boolean;
21
25
  user: any;
22
26
  emails?: { address: string; isPrimary?: boolean }[];
23
27
  handleAuthenticated?: () => void;
24
- onRequestEmailVerification?: (email: string) => Promise<{ success: boolean; message?: string } | void>;
25
- onVerifyEmail?: (email: string, code: string) => Promise<{ success: boolean; message?: string } | void>;
26
- onAddEmail?: (email: string) => Promise<{ success: boolean; message?: string } | void>;
28
+ onRequestEmailVerification?: (
29
+ email: string,
30
+ ) => Promise<{ success: boolean; message?: string } | void>;
31
+ onVerifyEmail?: (
32
+ email: string,
33
+ code: string,
34
+ ) => Promise<{ success: boolean; message?: string } | void>;
35
+ onAddEmail?: (
36
+ email: string,
37
+ ) => Promise<{ success: boolean; message?: string } | void>;
27
38
  }
28
39
 
29
40
  export const UserProfile = ({
@@ -34,12 +45,14 @@ export const UserProfile = ({
34
45
  onVerifyEmail,
35
46
  onAddEmail,
36
47
  }: UserProfileProps) => {
37
- const [isMounted, setIsMounted] = useState(false)
38
- const [activeTab, setActiveTab] = useState<"profile" | "security" | "preferences">("profile");
39
- const [verifyingEmail, setVerifyingEmail] = useState<string | null>(null)
40
- const [codeByEmail, setCodeByEmail] = useState<Record<string, string>>({})
41
- const [addingEmail, setAddingEmail] = useState<boolean>(false)
42
- const [newEmail, setNewEmail] = useState<string>("")
48
+ const [isMounted, setIsMounted] = useState(false);
49
+ const [activeTab, setActiveTab] = useState<
50
+ "profile" | "security" | "preferences"
51
+ >("profile");
52
+ const [verifyingEmail, setVerifyingEmail] = useState<string | null>(null);
53
+ const [codeByEmail, setCodeByEmail] = useState<Record<string, string>>({});
54
+ const [addingEmail, setAddingEmail] = useState<boolean>(false);
55
+ const [newEmail, setNewEmail] = useState<string>("");
43
56
 
44
57
  useEffect(() => {
45
58
  setIsMounted(true);
@@ -53,28 +66,30 @@ export const UserProfile = ({
53
66
 
54
67
  const iconProps: LucideProps = {
55
68
  className: "mr-2 h-4 w-4",
56
- "aria-hidden": "true"
57
- }
69
+ "aria-hidden": "true",
70
+ };
58
71
 
59
72
  const renderIcon = (Icon: any) => {
60
- if (!isMounted) return null
61
- return <Icon {...iconProps} />
62
- }
73
+ if (!isMounted) return null;
74
+ return <Icon {...iconProps} />;
75
+ };
63
76
 
64
77
  if (!isMounted || loading) {
65
- return <div>Loading...</div>
78
+ return <div>Loading...</div>;
66
79
  }
67
80
 
68
81
  if (!user) {
69
- return <div>No user</div>
82
+ return <div>No user</div>;
70
83
  }
71
-
84
+
72
85
  return (
73
86
  <div className="grid grid-cols-[14rem,1fr] w-full bg-transparent">
74
87
  <div className="h-full border-r border-border p-3 md:p-4 bg-transparent flex flex-col min-w-0">
75
88
  <div className="mb-3 md:mb-4">
76
89
  <h1 className="text-xl font-bold text-foreground">Account</h1>
77
- <p className="text-sm text-muted-foreground">Manage your account info.</p>
90
+ <p className="text-sm text-muted-foreground">
91
+ Manage your account info.
92
+ </p>
78
93
  </div>
79
94
 
80
95
  <nav className="space-y-1 flex-1">
@@ -89,7 +104,7 @@ export const UserProfile = ({
89
104
  {renderIcon(User)}
90
105
  Profile
91
106
  </button>
92
-
107
+
93
108
  {/* <button
94
109
  onClick={() => setActiveTab("security")}
95
110
  className={`flex items-center w-full px-3 py-2 text-sm rounded-md ${
@@ -121,8 +136,8 @@ export const UserProfile = ({
121
136
  {activeTab === "profile"
122
137
  ? "Profile details"
123
138
  : activeTab === "security"
124
- ? "Security settings"
125
- : "Preferences"}
139
+ ? "Security settings"
140
+ : "Preferences"}
126
141
  </h2>
127
142
  {/* <button className="text-gray-500 hover:text-gray-700">
128
143
  {renderIcon(X)}
@@ -133,14 +148,26 @@ export const UserProfile = ({
133
148
  <div className="space-y-5 md:space-y-6">
134
149
  {/* Profile Section */}
135
150
  <div>
136
- <h3 className="text-sm font-medium mb-3 text-foreground">Profile</h3>
151
+ <h3 className="text-sm font-medium mb-3 text-foreground">
152
+ Profile
153
+ </h3>
137
154
  <div className="flex items-center justify-between">
138
155
  <div className="flex items-center">
139
156
  <Avatar className="h-12 w-12 mr-4 border">
140
- <AvatarImage src={user.photos?.[0]?.value} alt="Profile picture" />
141
- <AvatarFallback>{user.displayName?.split(" ").map((n: string) => n[0]).join("")}</AvatarFallback>
157
+ <AvatarImage
158
+ src={user.photos?.[0]?.value}
159
+ alt="Profile picture"
160
+ />
161
+ <AvatarFallback>
162
+ {user.displayName
163
+ ?.split(" ")
164
+ .map((n: string) => n[0])
165
+ .join("")}
166
+ </AvatarFallback>
142
167
  </Avatar>
143
- <span className="font-medium text-foreground">{user.displayName}</span>
168
+ <span className="font-medium text-foreground">
169
+ {user.displayName}
170
+ </span>
144
171
  </div>
145
172
  {/* <Button variant="outline" size="sm">
146
173
  Edit profile
@@ -150,9 +177,10 @@ export const UserProfile = ({
150
177
 
151
178
  {/* Email Addresses Section */}
152
179
  <div>
153
- <h3 className="text-sm font-medium mb-3 text-foreground">Email addresses</h3>
180
+ <h3 className="text-sm font-medium mb-3 text-foreground">
181
+ Email addresses
182
+ </h3>
154
183
  <div className="space-y-2.5">
155
-
156
184
  {/* {JSON.stringify(user)} */}
157
185
 
158
186
  {/* {(emails.length > 0 ? emails : [{ address: user.email, isPrimary: true }]).map((email, i) => (
@@ -167,11 +195,16 @@ export const UserProfile = ({
167
195
  ))} */}
168
196
 
169
197
  {user.emails.map((email: any, idx: number) => {
170
- const v = (user?.verifications || []).find((ve: any) => ve.email === email.value)
171
- const isVerified = v?.verified === true
172
- const codeInput = codeByEmail[email.value] || ""
198
+ const v = (user?.verifications || []).find(
199
+ (ve: any) => ve.email === email.value,
200
+ );
201
+ const isVerified = v?.verified === true;
202
+ const codeInput = codeByEmail[email.value] || "";
173
203
  return (
174
- <div className="flex items-start justify-between gap-2" key={email.value}>
204
+ <div
205
+ className="flex items-start justify-between gap-2"
206
+ key={email.value}
207
+ >
175
208
  <div className="flex flex-col">
176
209
  <span className="text-foreground">{email.value}</span>
177
210
  <div className="mt-1">
@@ -203,13 +236,18 @@ export const UserProfile = ({
203
236
  className="h-7 w-24 text-sm rounded-md border border-border bg-background px-2 text-foreground"
204
237
  placeholder="Code"
205
238
  value={codeInput}
206
- onChange={(e) => setCodeByEmail((m) => ({ ...m, [email.value]: e.target.value }))}
239
+ onChange={(e) =>
240
+ setCodeByEmail((m) => ({
241
+ ...m,
242
+ [email.value]: e.target.value,
243
+ }))
244
+ }
207
245
  />
208
246
  <button
209
247
  className="h-7 rounded-md border border-border px-2 text-xs"
210
248
  onClick={async () => {
211
- if (!onVerifyEmail) return
212
- await onVerifyEmail(email.value, codeInput)
249
+ if (!onVerifyEmail) return;
250
+ await onVerifyEmail(email.value, codeInput);
213
251
  }}
214
252
  >
215
253
  Verify
@@ -226,8 +264,11 @@ export const UserProfile = ({
226
264
  <button
227
265
  className="h-7 rounded-md border border-border px-2 text-xs"
228
266
  onClick={async () => {
229
- if (onRequestEmailVerification) await onRequestEmailVerification(email.value)
230
- setVerifyingEmail(email.value)
267
+ if (onRequestEmailVerification)
268
+ await onRequestEmailVerification(
269
+ email.value,
270
+ );
271
+ setVerifyingEmail(email.value);
231
272
  }}
232
273
  >
233
274
  Send code
@@ -238,7 +279,7 @@ export const UserProfile = ({
238
279
  )}
239
280
  </div>
240
281
  </div>
241
- )
282
+ );
242
283
  })}
243
284
  <div className="mt-2">
244
285
  {addingEmail ? (
@@ -247,7 +288,8 @@ export const UserProfile = ({
247
288
  <CardHeader>
248
289
  <CardTitle>Add email address</CardTitle>
249
290
  <CardDescription>
250
- You'll need to verify this email address before it can be added to your account.
291
+ You'll need to verify this email address before it
292
+ can be added to your account.
251
293
  </CardDescription>
252
294
  </CardHeader>
253
295
  <CardContent>
@@ -260,11 +302,13 @@ export const UserProfile = ({
260
302
  onChange={(e) => setNewEmail(e.target.value)}
261
303
  onKeyDown={async (e) => {
262
304
  if (e.key === "Enter") {
263
- const v = String(newEmail || "").trim().toLowerCase()
264
- if (!v) return
265
- if (onAddEmail) await onAddEmail(v)
266
- setAddingEmail(false)
267
- setNewEmail("")
305
+ const v = String(newEmail || "")
306
+ .trim()
307
+ .toLowerCase();
308
+ if (!v) return;
309
+ if (onAddEmail) await onAddEmail(v);
310
+ setAddingEmail(false);
311
+ setNewEmail("");
268
312
  }
269
313
  }}
270
314
  />
@@ -274,19 +318,21 @@ export const UserProfile = ({
274
318
  <Button
275
319
  variant="ghost"
276
320
  onClick={() => {
277
- setAddingEmail(false)
278
- setNewEmail("")
321
+ setAddingEmail(false);
322
+ setNewEmail("");
279
323
  }}
280
324
  >
281
325
  Cancel
282
326
  </Button>
283
327
  <Button
284
328
  onClick={async () => {
285
- const v = String(newEmail || "").trim().toLowerCase()
286
- if (!v) return
287
- if (onAddEmail) await onAddEmail(v)
288
- setAddingEmail(false)
289
- setNewEmail("")
329
+ const v = String(newEmail || "")
330
+ .trim()
331
+ .toLowerCase();
332
+ if (!v) return;
333
+ if (onAddEmail) await onAddEmail(v);
334
+ setAddingEmail(false);
335
+ setNewEmail("");
290
336
  }}
291
337
  >
292
338
  Add
@@ -295,7 +341,12 @@ export const UserProfile = ({
295
341
  </Card>
296
342
  </div>
297
343
  ) : (
298
- <Button variant="outline" size="sm" className="text-xs" onClick={() => setAddingEmail(true)}>
344
+ <Button
345
+ variant="outline"
346
+ size="sm"
347
+ className="text-xs"
348
+ onClick={() => setAddingEmail(true)}
349
+ >
299
350
  Add email
300
351
  </Button>
301
352
  )}
@@ -322,16 +373,25 @@ export const UserProfile = ({
322
373
 
323
374
  {/* Connected Accounts Section */}
324
375
  <div>
325
- <h3 className="text-sm font-medium mb-3 text-gray-900 dark:text-gray-100">Connected accounts</h3>
376
+ <h3 className="text-sm font-medium mb-3 text-gray-900 dark:text-gray-100">
377
+ Connected accounts
378
+ </h3>
326
379
  <div className="space-y-2.5">
327
- <div className="flex items-center justify-between" key={user.provider}>
328
- <div className="flex items-center">
329
- <div className="mr-2">
330
- <span className="text-gray-900 dark:text-gray-100">{user.provider}</span>
331
- </div>
380
+ <div
381
+ className="flex items-center justify-between"
382
+ key={user.provider}
383
+ >
384
+ <div className="flex items-center">
385
+ <div className="mr-2">
386
+ <span className="text-gray-900 dark:text-gray-100">
387
+ {user.provider}
388
+ </span>
332
389
  </div>
333
- <span className="text-sm text-gray-500 dark:text-gray-400">{user?.emails?.[0]?.value}</span>
334
390
  </div>
391
+ <span className="text-sm text-gray-500 dark:text-gray-400">
392
+ {user?.emails?.[0]?.value}
393
+ </span>
394
+ </div>
335
395
  </div>
336
396
  </div>
337
397
  </div>
@@ -340,40 +400,62 @@ export const UserProfile = ({
340
400
  {/* Password row */}
341
401
  <div className="border rounded-md overflow-hidden">
342
402
  <div className="flex items-center justify-between px-4 py-3">
343
- <div className="text-sm text-gray-700 dark:text-gray-300">Password</div>
344
- <button className="text-sm text-indigo-600 hover:underline">Set password</button>
403
+ <div className="text-sm text-gray-700 dark:text-gray-300">
404
+ Password
405
+ </div>
406
+ <button className="text-sm text-indigo-600 hover:underline">
407
+ Set password
408
+ </button>
345
409
  </div>
346
410
  </div>
347
411
 
348
412
  {/* Passkeys row */}
349
413
  <div className="border rounded-md overflow-hidden">
350
414
  <div className="flex items-center justify-between px-4 py-3">
351
- <div className="text-sm text-gray-700 dark:text-gray-300">Passkeys</div>
352
- <button className="text-sm text-indigo-600 hover:underline">+&nbsp;Add a passkey</button>
415
+ <div className="text-sm text-gray-700 dark:text-gray-300">
416
+ Passkeys
417
+ </div>
418
+ <button className="text-sm text-indigo-600 hover:underline">
419
+ +&nbsp;Add a passkey
420
+ </button>
353
421
  </div>
354
422
  </div>
355
423
 
356
424
  {/* Two-step verification row */}
357
425
  <div className="border rounded-md overflow-hidden">
358
426
  <div className="flex items-center justify-between px-4 py-3">
359
- <div className="text-sm text-gray-700 dark:text-gray-300">Two-step verification</div>
360
- <button className="text-sm text-indigo-600 hover:underline">+&nbsp;Add two-step verification</button>
427
+ <div className="text-sm text-gray-700 dark:text-gray-300">
428
+ Two-step verification
429
+ </div>
430
+ <button className="text-sm text-indigo-600 hover:underline">
431
+ +&nbsp;Add two-step verification
432
+ </button>
361
433
  </div>
362
434
  </div>
363
435
 
364
436
  {/* Active devices list (scaffold) */}
365
437
  <div className="border rounded-md overflow-hidden">
366
- <div className="px-4 py-3 border-b text-sm font-medium text-gray-900 dark:text-gray-100">Active devices</div>
438
+ <div className="px-4 py-3 border-b text-sm font-medium text-gray-900 dark:text-gray-100">
439
+ Active devices
440
+ </div>
367
441
  <div className="p-4 space-y-3">
368
442
  <div className="text-sm">
369
443
  <div className="flex items-center gap-2">
370
444
  <span className="inline-block h-5 w-5 rounded-sm bg-gray-900 dark:bg-white" />
371
445
  <span className="font-medium">X11</span>
372
- <span className="text-xs rounded-md border px-2 py-0.5 text-gray-600 dark:text-gray-300">This device</span>
446
+ <span className="text-xs rounded-md border px-2 py-0.5 text-gray-600 dark:text-gray-300">
447
+ This device
448
+ </span>
449
+ </div>
450
+ <div className="text-gray-600 dark:text-gray-400 mt-1">
451
+ Firefox 142.0
452
+ </div>
453
+ <div className="text-gray-600 dark:text-gray-400">
454
+ 127.0.0.1 (Local), (Your City)
455
+ </div>
456
+ <div className="text-gray-600 dark:text-gray-400">
457
+ Today at 7:08 PM
373
458
  </div>
374
- <div className="text-gray-600 dark:text-gray-400 mt-1">Firefox 142.0</div>
375
- <div className="text-gray-600 dark:text-gray-400">127.0.0.1 (Local), (Your City)</div>
376
- <div className="text-gray-600 dark:text-gray-400">Today at 7:08 PM</div>
377
459
  </div>
378
460
  </div>
379
461
  </div>
@@ -381,8 +463,12 @@ export const UserProfile = ({
381
463
  {/* Delete account */}
382
464
  <div className="border rounded-md overflow-hidden">
383
465
  <div className="flex items-center justify-between px-4 py-3">
384
- <div className="text-sm text-gray-700 dark:text-gray-300">Delete account</div>
385
- <button className="text-sm text-red-600 hover:underline">Delete account</button>
466
+ <div className="text-sm text-gray-700 dark:text-gray-300">
467
+ Delete account
468
+ </div>
469
+ <button className="text-sm text-red-600 hover:underline">
470
+ Delete account
471
+ </button>
386
472
  </div>
387
473
  </div>
388
474
  </div>
@@ -390,15 +476,23 @@ export const UserProfile = ({
390
476
  <div className="space-y-5 md:space-y-6">
391
477
  {/* Preferences */}
392
478
  <div>
393
- <h3 className="text-sm font-medium mb-3 text-gray-900 dark:text-gray-100">Preferences</h3>
479
+ <h3 className="text-sm font-medium mb-3 text-gray-900 dark:text-gray-100">
480
+ Preferences
481
+ </h3>
394
482
  <div className="space-y-3 text-sm">
395
483
  <div className="flex items-center justify-between">
396
- <span className="text-gray-700 dark:text-gray-300">Locale</span>
484
+ <span className="text-gray-700 dark:text-gray-300">
485
+ Locale
486
+ </span>
397
487
  <span className="text-gray-500 dark:text-gray-400">Auto</span>
398
488
  </div>
399
489
  <div className="flex items-center justify-between">
400
- <span className="text-gray-700 dark:text-gray-300">Theme</span>
401
- <span className="text-gray-500 dark:text-gray-400">System</span>
490
+ <span className="text-gray-700 dark:text-gray-300">
491
+ Theme
492
+ </span>
493
+ <span className="text-gray-500 dark:text-gray-400">
494
+ System
495
+ </span>
402
496
  </div>
403
497
  </div>
404
498
  </div>
@@ -423,5 +517,5 @@ export const UserProfile = ({
423
517
  </span>
424
518
  </div> */}
425
519
  </div>
426
- )
427
- }
520
+ );
521
+ };
@@ -1,15 +1,22 @@
1
- "use client"
1
+ "use client";
2
2
 
3
- import type React from "react"
3
+ import type React from "react";
4
4
 
5
- import { useState } from "react"
6
- import { Button } from "../../components/ui/button"
7
- import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "../../components/ui/card"
8
- import { Input } from "../../components/ui/input"
9
- import { Label } from "../../components/ui/label"
10
- import { Separator } from "../../components/ui/separator"
11
- import { Github, AlertCircle } from "lucide-react"
12
- import { Alert, AlertDescription } from "../../components/ui/alert"
5
+ import { useState } from "react";
6
+ import { Button } from "../../components/ui/button";
7
+ import {
8
+ Card,
9
+ CardContent,
10
+ CardDescription,
11
+ CardFooter,
12
+ CardHeader,
13
+ CardTitle,
14
+ } from "../../components/ui/card";
15
+ import { Input } from "../../components/ui/input";
16
+ import { Label } from "../../components/ui/label";
17
+ import { Separator } from "../../components/ui/separator";
18
+ import { Github, AlertCircle } from "lucide-react";
19
+ import { Alert, AlertDescription } from "../../components/ui/alert";
13
20
 
14
21
  export const LoginForm = () => {
15
22
  const [email, setEmail] = useState("");
@@ -18,39 +25,42 @@ export const LoginForm = () => {
18
25
  const [isLoading, setIsLoading] = useState(false);
19
26
 
20
27
  const handleEmailLogin = async (e: React.FormEvent) => {
21
- e.preventDefault()
22
- setIsLoading(true)
23
- setError("")
28
+ e.preventDefault();
29
+ setIsLoading(true);
30
+ setError("");
24
31
 
25
32
  try {
26
- await new Promise((resolve) => setTimeout(resolve, 1000))
33
+ await new Promise((resolve) => setTimeout(resolve, 1000));
27
34
  } catch (err) {
28
- setError("Invalid email or password")
35
+ setError("Invalid email or password");
29
36
  } finally {
30
- setIsLoading(false)
37
+ setIsLoading(false);
31
38
  }
32
- }
39
+ };
33
40
 
34
41
  const handleOAuthLogin = async (provider: string) => {
35
- setIsLoading(true)
36
- setError("")
42
+ setIsLoading(true);
43
+ setError("");
37
44
 
38
45
  try {
39
-
40
- await new Promise((resolve) => setTimeout(resolve, 1000))
46
+ await new Promise((resolve) => setTimeout(resolve, 1000));
41
47
  } catch (err) {
42
- setError(`Failed to login with ${provider}`)
48
+ setError(`Failed to login with ${provider}`);
43
49
  } finally {
44
- setIsLoading(false)
50
+ setIsLoading(false);
45
51
  }
46
- }
52
+ };
47
53
 
48
54
  return (
49
55
  <div className="flex min-h-screen items-center justify-center bg-gray-50 px-4 py-12 sm:px-6 lg:px-8">
50
56
  <Card className="w-full max-w-md">
51
57
  <CardHeader className="space-y-1">
52
- <CardTitle className="text-2xl font-bold text-center">Login</CardTitle>
53
- <CardDescription className="text-center">Choose your preferred login method</CardDescription>
58
+ <CardTitle className="text-2xl font-bold text-center">
59
+ Login
60
+ </CardTitle>
61
+ <CardDescription className="text-center">
62
+ Choose your preferred login method
63
+ </CardDescription>
54
64
  </CardHeader>
55
65
  <CardContent className="space-y-4">
56
66
  {error && (
@@ -122,7 +132,10 @@ export const LoginForm = () => {
122
132
  <div className="space-y-2">
123
133
  <div className="flex items-center justify-between">
124
134
  <Label htmlFor="password">Password</Label>
125
- <a href="/forgot-password" className="text-xs text-primary hover:underline">
135
+ <a
136
+ href="/forgot-password"
137
+ className="text-xs text-primary hover:underline"
138
+ >
126
139
  Forgot password?
127
140
  </a>
128
141
  </div>
@@ -150,5 +163,5 @@ export const LoginForm = () => {
150
163
  </CardFooter>
151
164
  </Card>
152
165
  </div>
153
- )
154
- }
166
+ );
167
+ };