@authdog/react-elements 0.0.38 → 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 +44 -41
  2. package/CHANGELOG.md +12 -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 +3 -3
  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 -85
  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,6 +104,7 @@ export const UserProfile = ({
89
104
  {renderIcon(User)}
90
105
  Profile
91
106
  </button>
107
+
92
108
  {/* <button
93
109
  onClick={() => setActiveTab("security")}
94
110
  className={`flex items-center w-full px-3 py-2 text-sm rounded-md ${
@@ -120,8 +136,8 @@ export const UserProfile = ({
120
136
  {activeTab === "profile"
121
137
  ? "Profile details"
122
138
  : activeTab === "security"
123
- ? "Security settings"
124
- : "Preferences"}
139
+ ? "Security settings"
140
+ : "Preferences"}
125
141
  </h2>
126
142
  {/* <button className="text-gray-500 hover:text-gray-700">
127
143
  {renderIcon(X)}
@@ -132,14 +148,26 @@ export const UserProfile = ({
132
148
  <div className="space-y-5 md:space-y-6">
133
149
  {/* Profile Section */}
134
150
  <div>
135
- <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>
136
154
  <div className="flex items-center justify-between">
137
155
  <div className="flex items-center">
138
156
  <Avatar className="h-12 w-12 mr-4 border">
139
- <AvatarImage src={user.photos?.[0]?.value} alt="Profile picture" />
140
- <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>
141
167
  </Avatar>
142
- <span className="font-medium text-foreground">{user.displayName}</span>
168
+ <span className="font-medium text-foreground">
169
+ {user.displayName}
170
+ </span>
143
171
  </div>
144
172
  {/* <Button variant="outline" size="sm">
145
173
  Edit profile
@@ -149,9 +177,10 @@ export const UserProfile = ({
149
177
 
150
178
  {/* Email Addresses Section */}
151
179
  <div>
152
- <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>
153
183
  <div className="space-y-2.5">
154
-
155
184
  {/* {JSON.stringify(user)} */}
156
185
 
157
186
  {/* {(emails.length > 0 ? emails : [{ address: user.email, isPrimary: true }]).map((email, i) => (
@@ -166,11 +195,16 @@ export const UserProfile = ({
166
195
  ))} */}
167
196
 
168
197
  {user.emails.map((email: any, idx: number) => {
169
- const v = (user?.verifications || []).find((ve: any) => ve.email === email.value)
170
- const isVerified = v?.verified === true
171
- 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] || "";
172
203
  return (
173
- <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
+ >
174
208
  <div className="flex flex-col">
175
209
  <span className="text-foreground">{email.value}</span>
176
210
  <div className="mt-1">
@@ -202,13 +236,18 @@ export const UserProfile = ({
202
236
  className="h-7 w-24 text-sm rounded-md border border-border bg-background px-2 text-foreground"
203
237
  placeholder="Code"
204
238
  value={codeInput}
205
- 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
+ }
206
245
  />
207
246
  <button
208
247
  className="h-7 rounded-md border border-border px-2 text-xs"
209
248
  onClick={async () => {
210
- if (!onVerifyEmail) return
211
- await onVerifyEmail(email.value, codeInput)
249
+ if (!onVerifyEmail) return;
250
+ await onVerifyEmail(email.value, codeInput);
212
251
  }}
213
252
  >
214
253
  Verify
@@ -225,8 +264,11 @@ export const UserProfile = ({
225
264
  <button
226
265
  className="h-7 rounded-md border border-border px-2 text-xs"
227
266
  onClick={async () => {
228
- if (onRequestEmailVerification) await onRequestEmailVerification(email.value)
229
- setVerifyingEmail(email.value)
267
+ if (onRequestEmailVerification)
268
+ await onRequestEmailVerification(
269
+ email.value,
270
+ );
271
+ setVerifyingEmail(email.value);
230
272
  }}
231
273
  >
232
274
  Send code
@@ -237,7 +279,7 @@ export const UserProfile = ({
237
279
  )}
238
280
  </div>
239
281
  </div>
240
- )
282
+ );
241
283
  })}
242
284
  <div className="mt-2">
243
285
  {addingEmail ? (
@@ -246,7 +288,8 @@ export const UserProfile = ({
246
288
  <CardHeader>
247
289
  <CardTitle>Add email address</CardTitle>
248
290
  <CardDescription>
249
- 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.
250
293
  </CardDescription>
251
294
  </CardHeader>
252
295
  <CardContent>
@@ -259,11 +302,13 @@ export const UserProfile = ({
259
302
  onChange={(e) => setNewEmail(e.target.value)}
260
303
  onKeyDown={async (e) => {
261
304
  if (e.key === "Enter") {
262
- const v = String(newEmail || "").trim().toLowerCase()
263
- if (!v) return
264
- if (onAddEmail) await onAddEmail(v)
265
- setAddingEmail(false)
266
- 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("");
267
312
  }
268
313
  }}
269
314
  />
@@ -273,19 +318,21 @@ export const UserProfile = ({
273
318
  <Button
274
319
  variant="ghost"
275
320
  onClick={() => {
276
- setAddingEmail(false)
277
- setNewEmail("")
321
+ setAddingEmail(false);
322
+ setNewEmail("");
278
323
  }}
279
324
  >
280
325
  Cancel
281
326
  </Button>
282
327
  <Button
283
328
  onClick={async () => {
284
- const v = String(newEmail || "").trim().toLowerCase()
285
- if (!v) return
286
- if (onAddEmail) await onAddEmail(v)
287
- setAddingEmail(false)
288
- 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("");
289
336
  }}
290
337
  >
291
338
  Add
@@ -294,7 +341,12 @@ export const UserProfile = ({
294
341
  </Card>
295
342
  </div>
296
343
  ) : (
297
- <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
+ >
298
350
  Add email
299
351
  </Button>
300
352
  )}
@@ -321,16 +373,25 @@ export const UserProfile = ({
321
373
 
322
374
  {/* Connected Accounts Section */}
323
375
  <div>
324
- <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>
325
379
  <div className="space-y-2.5">
326
- <div className="flex items-center justify-between" key={user.provider}>
327
- <div className="flex items-center">
328
- <div className="mr-2">
329
- <span className="text-gray-900 dark:text-gray-100">{user.provider}</span>
330
- </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>
331
389
  </div>
332
- <span className="text-sm text-gray-500 dark:text-gray-400">{user?.emails?.[0]?.value}</span>
333
390
  </div>
391
+ <span className="text-sm text-gray-500 dark:text-gray-400">
392
+ {user?.emails?.[0]?.value}
393
+ </span>
394
+ </div>
334
395
  </div>
335
396
  </div>
336
397
  </div>
@@ -339,40 +400,62 @@ export const UserProfile = ({
339
400
  {/* Password row */}
340
401
  <div className="border rounded-md overflow-hidden">
341
402
  <div className="flex items-center justify-between px-4 py-3">
342
- <div className="text-sm text-gray-700 dark:text-gray-300">Password</div>
343
- <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>
344
409
  </div>
345
410
  </div>
346
411
 
347
412
  {/* Passkeys row */}
348
413
  <div className="border rounded-md overflow-hidden">
349
414
  <div className="flex items-center justify-between px-4 py-3">
350
- <div className="text-sm text-gray-700 dark:text-gray-300">Passkeys</div>
351
- <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>
352
421
  </div>
353
422
  </div>
354
423
 
355
424
  {/* Two-step verification row */}
356
425
  <div className="border rounded-md overflow-hidden">
357
426
  <div className="flex items-center justify-between px-4 py-3">
358
- <div className="text-sm text-gray-700 dark:text-gray-300">Two-step verification</div>
359
- <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>
360
433
  </div>
361
434
  </div>
362
435
 
363
436
  {/* Active devices list (scaffold) */}
364
437
  <div className="border rounded-md overflow-hidden">
365
- <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>
366
441
  <div className="p-4 space-y-3">
367
442
  <div className="text-sm">
368
443
  <div className="flex items-center gap-2">
369
444
  <span className="inline-block h-5 w-5 rounded-sm bg-gray-900 dark:bg-white" />
370
445
  <span className="font-medium">X11</span>
371
- <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
372
458
  </div>
373
- <div className="text-gray-600 dark:text-gray-400 mt-1">Firefox 142.0</div>
374
- <div className="text-gray-600 dark:text-gray-400">127.0.0.1 (Local), (Your City)</div>
375
- <div className="text-gray-600 dark:text-gray-400">Today at 7:08 PM</div>
376
459
  </div>
377
460
  </div>
378
461
  </div>
@@ -380,8 +463,12 @@ export const UserProfile = ({
380
463
  {/* Delete account */}
381
464
  <div className="border rounded-md overflow-hidden">
382
465
  <div className="flex items-center justify-between px-4 py-3">
383
- <div className="text-sm text-gray-700 dark:text-gray-300">Delete account</div>
384
- <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>
385
472
  </div>
386
473
  </div>
387
474
  </div>
@@ -389,15 +476,23 @@ export const UserProfile = ({
389
476
  <div className="space-y-5 md:space-y-6">
390
477
  {/* Preferences */}
391
478
  <div>
392
- <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>
393
482
  <div className="space-y-3 text-sm">
394
483
  <div className="flex items-center justify-between">
395
- <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>
396
487
  <span className="text-gray-500 dark:text-gray-400">Auto</span>
397
488
  </div>
398
489
  <div className="flex items-center justify-between">
399
- <span className="text-gray-700 dark:text-gray-300">Theme</span>
400
- <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>
401
496
  </div>
402
497
  </div>
403
498
  </div>
@@ -422,5 +517,5 @@ export const UserProfile = ({
422
517
  </span>
423
518
  </div> */}
424
519
  </div>
425
- )
426
- }
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
+ };