authverse 1.0.6 → 1.0.7-canary.2

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.
@@ -0,0 +1,128 @@
1
+ import { useForm } from "@tanstack/react-form";
2
+ import { toast } from "sonner";
3
+ import * as z from "zod";
4
+ import { Button } from "@/components/ui/button";
5
+ import {
6
+ Card,
7
+ CardContent,
8
+ CardDescription,
9
+ CardFooter,
10
+ CardHeader,
11
+ CardTitle,
12
+ } from "@/components/ui/card";
13
+ import {
14
+ Field,
15
+ FieldError,
16
+ FieldGroup,
17
+ FieldLabel,
18
+ } from "@/components/ui/field";
19
+ import { Input } from "@/components/ui/input";
20
+ import { useState } from "react";
21
+ import { Link } from "@tanstack/react-router";
22
+ import { authClient } from "@/lib/auth-client";
23
+
24
+ const formSchema = z.object({
25
+ email: z.string().email(),
26
+ });
27
+
28
+ const ForgetComponent = () => {
29
+ const [isLoading, setIsLoading] = useState(false);
30
+
31
+ const form = useForm({
32
+ defaultValues: {
33
+ email: "",
34
+ },
35
+ validators: {
36
+ onSubmit: formSchema,
37
+ },
38
+ onSubmit: async ({ value }) => {
39
+ setIsLoading(true);
40
+ await authClient.requestPasswordReset(
41
+ {
42
+ email: value.email,
43
+ redirectTo: "/auth/reset-password",
44
+ },
45
+ {
46
+ onSuccess: () => {
47
+ toast.success(
48
+ "Password reset email sent. Please check your inbox."
49
+ );
50
+ },
51
+ onError: (error: any) => {
52
+ setIsLoading(false);
53
+ toast.error(error.error.message);
54
+ },
55
+ }
56
+ );
57
+ },
58
+ });
59
+
60
+ return (
61
+ <Card className="w-full sm:max-w-md shadow-md">
62
+ <CardHeader>
63
+ <CardTitle className="text-2xl leading-4">Forger Password</CardTitle>
64
+ <CardDescription>Please enter your email</CardDescription>
65
+ </CardHeader>
66
+ <CardContent>
67
+ <form
68
+ id="form-login"
69
+ onSubmit={(e) => {
70
+ e.preventDefault();
71
+ form.handleSubmit();
72
+ }}
73
+ >
74
+ <FieldGroup>
75
+ <form.Field
76
+ name="email"
77
+ children={(field) => {
78
+ const isInvalid =
79
+ field.state.meta.isTouched && !field.state.meta.isValid;
80
+ return (
81
+ <Field data-invalid={isInvalid}>
82
+ <FieldLabel htmlFor={field.name}>Email</FieldLabel>
83
+ <Input
84
+ id={field.name}
85
+ name={field.name}
86
+ value={field.state.value}
87
+ onBlur={field.handleBlur}
88
+ onChange={(e) => field.handleChange(e.target.value)}
89
+ aria-invalid={isInvalid}
90
+ placeholder="example@example.com"
91
+ autoComplete="off"
92
+ disabled={isLoading}
93
+ />
94
+ {isInvalid && (
95
+ <FieldError errors={field.state.meta.errors} />
96
+ )}
97
+ </Field>
98
+ );
99
+ }}
100
+ />
101
+ </FieldGroup>
102
+ </form>
103
+ </CardContent>
104
+ <CardFooter>
105
+ <div className="w-full">
106
+ <Field orientation="horizontal">
107
+ <Button
108
+ type="submit"
109
+ form="form-login"
110
+ className="w-full"
111
+ disabled={isLoading}
112
+ >
113
+ {isLoading ? "Resetting..." : "Reset Password"}
114
+ </Button>
115
+ </Field>
116
+ <div className="w-full text-center pt-4 space-x-2">
117
+ <span>Already have an account?</span>
118
+ <Link to="/auth/login" className="underline">
119
+ Login
120
+ </Link>
121
+ </div>
122
+ </div>
123
+ </CardFooter>
124
+ </Card>
125
+ );
126
+ };
127
+
128
+ export default ForgetComponent;
@@ -0,0 +1,34 @@
1
+ import { authClient } from "@/lib/auth-client";
2
+ import { Button } from "../ui/button";
3
+
4
+ const GithubProviders = () => {
5
+ const signIn = async () => {
6
+ await authClient.signIn.social({
7
+ provider: "github",
8
+ });
9
+ };
10
+
11
+ return (
12
+ <Button
13
+ className="w-full text-base flex items-center gap-2"
14
+ variant="outline"
15
+ onClick={signIn}
16
+ >
17
+ {/* GitHub SVG Icon */}
18
+ <svg
19
+ width="20"
20
+ height="20"
21
+ viewBox="0 0 24 24"
22
+ fill="currentColor"
23
+ xmlns="http://www.w3.org/2000/svg"
24
+ className="text-black dark:text-white"
25
+ >
26
+ <path d="M12 .5C5.73.5.5 5.74.5 12.03c0 5.13 3.29 9.47 7.86 11 .58.1.79-.25.79-.56v-2.1c-3.2.7-3.88-1.54-3.88-1.54-.52-1.33-1.27-1.69-1.27-1.69-1.04-.72.08-.7.08-.7 1.15.08 1.75 1.19 1.75 1.19 1.02 1.75 2.68 1.24 3.34.95.1-.74.4-1.24.73-1.53-2.55-.29-5.23-1.28-5.23-5.7 0-1.26.45-2.3 1.19-3.11-.12-.29-.52-1.45.11-3.02 0 0 .97-.31 3.18 1.19.92-.26 1.9-.39 2.88-.39.98 0 1.96.13 2.88.39 2.2-1.5 3.17-1.19 3.17-1.19.63 1.57.23 2.73.11 3.02.74.81 1.19 1.85 1.19 3.11 0 4.43-2.69 5.4-5.25 5.68.41.35.77 1.04.77 2.1v3.11c0 .31.21.67.8.56 4.57-1.53 7.85-5.87 7.85-11C23.5 5.74 18.27.5 12 .5z" />
27
+ </svg>
28
+
29
+ <span>Sign in with GitHub</span>
30
+ </Button>
31
+ );
32
+ };
33
+
34
+ export default GithubProviders;
@@ -0,0 +1,46 @@
1
+ import { authClient } from "@/lib/auth-client";
2
+ import { Button } from "../ui/button";
3
+
4
+ const GoogleProviders = () => {
5
+ const signIn = async () => {
6
+ await authClient.signIn.social({
7
+ provider: "google",
8
+ });
9
+ };
10
+
11
+ return (
12
+ <Button
13
+ className="w-full text-base flex items-center gap-2"
14
+ variant="outline"
15
+ onClick={signIn}
16
+ >
17
+ <svg
18
+ width="20"
19
+ height="20"
20
+ viewBox="0 0 48 48"
21
+ xmlns="http://www.w3.org/2000/svg"
22
+ >
23
+ <path
24
+ fill="#EA4335"
25
+ d="M24 9.5c3.54 0 6.7 1.23 9.2 3.64l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.2C12.43 13.02 17.74 9.5 24 9.5z"
26
+ />
27
+ <path
28
+ fill="#4285F4"
29
+ d="M46.98 24.55c0-1.64-.15-3.22-.43-4.76H24v9.02h12.95c-.56 3.01-2.24 5.56-4.78 7.28l7.73 5.99c4.51-4.18 7.08-10.35 7.08-17.53z"
30
+ />
31
+ <path
32
+ fill="#FBBC05"
33
+ d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.2C.92 16.46 0 20.12 0 24s.92 7.54 2.56 10.79l7.97-6.2z"
34
+ />
35
+ <path
36
+ fill="#34A853"
37
+ d="M24 48c6.48 0 11.93-2.13 15.9-5.81l-7.73-5.99c-2.15 1.45-4.9 2.3-8.17 2.3-6.26 0-11.57-3.52-13.46-8.59l-7.97 6.2C6.51 42.62 14.62 48 24 48z"
38
+ />
39
+ </svg>
40
+
41
+ <span>Sign in with Google</span>
42
+ </Button>
43
+ );
44
+ };
45
+
46
+ export default GoogleProviders;
@@ -0,0 +1,159 @@
1
+ import { useForm } from "@tanstack/react-form";
2
+ // import { Controller } from "@tanstack/react-form";
3
+ import { toast } from "sonner";
4
+ import * as z from "zod";
5
+ import { Button } from "@/components/ui/button";
6
+ import {
7
+ Card,
8
+ CardContent,
9
+ CardDescription,
10
+ CardFooter,
11
+ CardHeader,
12
+ CardTitle,
13
+ } from "@/components/ui/card";
14
+ import {
15
+ Field,
16
+ FieldError,
17
+ FieldGroup,
18
+ FieldLabel,
19
+ } from "@/components/ui/field";
20
+ import { Input } from "@/components/ui/input";
21
+ import { useState } from "react";
22
+ import { Link } from "@tanstack/react-router";
23
+ import { authClient } from "@/lib/auth-client";
24
+
25
+ const formSchema = z.object({
26
+ email: z.string().email(),
27
+ password: z.string().min(8, {
28
+ message: "Password must be at least 8 characters",
29
+ }),
30
+ });
31
+
32
+ const LoginComponent = () => {
33
+ const [isLoading, setIsLoading] = useState(false);
34
+
35
+ const form = useForm({
36
+ defaultValues: {
37
+ email: "",
38
+ password: "",
39
+ },
40
+ validators: {
41
+ onSubmit: formSchema,
42
+ },
43
+ onSubmit: async ({ value }) => {
44
+ setIsLoading(true);
45
+ await authClient.signIn.email(
46
+ {
47
+ email: value.email,
48
+ password: value.password,
49
+ callbackURL: "/",
50
+ },
51
+ {
52
+ onSuccess: () => {
53
+ toast.success("Login successful!");
54
+ },
55
+ onError: (error: any) => {
56
+ setIsLoading(false);
57
+ toast.error(error.error.message);
58
+ },
59
+ }
60
+ );
61
+ },
62
+ });
63
+
64
+ return (
65
+ <Card className="w-full sm:max-w-md shadow-md">
66
+ <CardHeader>
67
+ <CardTitle className="text-2xl leading-4">Welcome Back</CardTitle>
68
+ <CardDescription>Please sign in to your account.</CardDescription>
69
+ </CardHeader>
70
+ <CardContent>
71
+ <form
72
+ id="form-login"
73
+ onSubmit={(e) => {
74
+ e.preventDefault();
75
+ form.handleSubmit();
76
+ }}
77
+ >
78
+ <FieldGroup>
79
+ <form.Field
80
+ name="email"
81
+ children={(field) => {
82
+ const isInvalid =
83
+ field.state.meta.isTouched && !field.state.meta.isValid;
84
+ return (
85
+ <Field data-invalid={isInvalid}>
86
+ <FieldLabel htmlFor={field.name}>Email</FieldLabel>
87
+ <Input
88
+ id={field.name}
89
+ name={field.name}
90
+ value={field.state.value}
91
+ onBlur={field.handleBlur}
92
+ onChange={(e) => field.handleChange(e.target.value)}
93
+ aria-invalid={isInvalid}
94
+ placeholder="example@example.com"
95
+ autoComplete="off"
96
+ disabled={isLoading}
97
+ />
98
+ {isInvalid && (
99
+ <FieldError errors={field.state.meta.errors} />
100
+ )}
101
+ </Field>
102
+ );
103
+ }}
104
+ />
105
+ <form.Field
106
+ name="password"
107
+ children={(field) => {
108
+ const isInvalid =
109
+ field.state.meta.isTouched && !field.state.meta.isValid;
110
+ return (
111
+ <Field data-invalid={isInvalid}>
112
+ <FieldLabel htmlFor={field.name}>Password</FieldLabel>
113
+ <Input
114
+ id={field.name}
115
+ name={field.name}
116
+ value={field.state.value}
117
+ onBlur={field.handleBlur}
118
+ onChange={(e) => field.handleChange(e.target.value)}
119
+ aria-invalid={isInvalid}
120
+ placeholder="********"
121
+ type="password"
122
+ autoComplete="off"
123
+ disabled={isLoading}
124
+ />
125
+ {isInvalid && (
126
+ <FieldError errors={field.state.meta.errors} />
127
+ )}
128
+ </Field>
129
+ );
130
+ }}
131
+ />
132
+ </FieldGroup>
133
+ </form>
134
+ </CardContent>
135
+ <CardFooter>
136
+ <div className="w-full">
137
+ <Field orientation="horizontal">
138
+ <Button
139
+ type="submit"
140
+ form="form-login"
141
+ className="w-full"
142
+ disabled={isLoading}
143
+ >
144
+ {isLoading ? "Logining..." : "Login"}
145
+ </Button>
146
+ </Field>
147
+ <div className="w-full text-center pt-4 space-x-2">
148
+ <span>Don&apos;t have an account?</span>
149
+ <Link to="/auth/signup" className="underline">
150
+ Sing up
151
+ </Link>
152
+ </div>
153
+ </div>
154
+ </CardFooter>
155
+ </Card>
156
+ );
157
+ };
158
+
159
+ export default LoginComponent;
@@ -0,0 +1,163 @@
1
+ import { useForm } from "@tanstack/react-form";
2
+ import { toast } from "sonner";
3
+ import * as z from "zod";
4
+ import { Button } from "@/components/ui/button";
5
+ import {
6
+ Card,
7
+ CardContent,
8
+ CardDescription,
9
+ CardFooter,
10
+ CardHeader,
11
+ CardTitle,
12
+ } from "@/components/ui/card";
13
+ import {
14
+ Field,
15
+ FieldError,
16
+ FieldGroup,
17
+ FieldLabel,
18
+ } from "@/components/ui/field";
19
+ import { Input } from "@/components/ui/input";
20
+ import { useState } from "react";
21
+ import { authClient } from "@/lib/auth-client";
22
+ import { redirect, useSearch } from "@tanstack/react-router";
23
+
24
+ const formSchema = z
25
+ .object({
26
+ password: z.string().min(8, {
27
+ message: "Password must be at least 8 characters",
28
+ }),
29
+ confirmPassword: z.string(),
30
+ })
31
+ .refine((data) => data.password === data.confirmPassword, {
32
+ message: "Passwords do not match",
33
+ path: ["confirmPassword"],
34
+ });
35
+
36
+ const ResetComponent = () => {
37
+ const [isLoading, setIsLoading] = useState(false);
38
+ const { token } = useSearch({ from: "/auth/reset-password" });
39
+
40
+ const form = useForm({
41
+ defaultValues: {
42
+ password: "",
43
+ confirmPassword: "",
44
+ },
45
+ validators: {
46
+ onSubmit: formSchema,
47
+ },
48
+ onSubmit: async ({ value }) => {
49
+ setIsLoading(true);
50
+ await authClient.resetPassword(
51
+ {
52
+ newPassword: value.password,
53
+ token,
54
+ },
55
+ {
56
+ onSuccess: () => {
57
+ toast.success(
58
+ "Password has been reset successfully. You can now log in with your new password."
59
+ );
60
+ redirect({ to: "/" });
61
+ },
62
+ onError: (error: any) => {
63
+ setIsLoading(false);
64
+ toast.error(error.error.message);
65
+ },
66
+ }
67
+ );
68
+ },
69
+ });
70
+
71
+ return (
72
+ <Card className="w-full sm:max-w-md shadow-md">
73
+ <CardHeader>
74
+ <CardTitle className="text-2xl leading-4">Reset Password</CardTitle>
75
+ <CardDescription>Please enter your new password</CardDescription>
76
+ </CardHeader>
77
+ <CardContent>
78
+ <form
79
+ id="form-login"
80
+ onSubmit={(e) => {
81
+ e.preventDefault();
82
+ form.handleSubmit();
83
+ }}
84
+ >
85
+ <FieldGroup>
86
+ <form.Field
87
+ name="password"
88
+ children={(field) => {
89
+ const isInvalid =
90
+ field.state.meta.isTouched && !field.state.meta.isValid;
91
+ return (
92
+ <Field data-invalid={isInvalid}>
93
+ <FieldLabel htmlFor={field.name}>Password</FieldLabel>
94
+ <Input
95
+ id={field.name}
96
+ name={field.name}
97
+ value={field.state.value}
98
+ onBlur={field.handleBlur}
99
+ onChange={(e) => field.handleChange(e.target.value)}
100
+ aria-invalid={isInvalid}
101
+ placeholder="New Password"
102
+ type="password"
103
+ autoComplete="off"
104
+ disabled={isLoading}
105
+ />
106
+ {isInvalid && (
107
+ <FieldError errors={field.state.meta.errors} />
108
+ )}
109
+ </Field>
110
+ );
111
+ }}
112
+ />
113
+ <form.Field
114
+ name="confirmPassword"
115
+ children={(field) => {
116
+ const isInvalid =
117
+ field.state.meta.isTouched && !field.state.meta.isValid;
118
+ return (
119
+ <Field data-invalid={isInvalid}>
120
+ <FieldLabel htmlFor={field.name}>
121
+ Confirm Password
122
+ </FieldLabel>
123
+ <Input
124
+ id={field.name}
125
+ name={field.name}
126
+ value={field.state.value}
127
+ onBlur={field.handleBlur}
128
+ onChange={(e) => field.handleChange(e.target.value)}
129
+ aria-invalid={isInvalid}
130
+ placeholder="Confirm Password"
131
+ type="password"
132
+ autoComplete="off"
133
+ disabled={isLoading}
134
+ />
135
+ {isInvalid && (
136
+ <FieldError errors={field.state.meta.errors} />
137
+ )}
138
+ </Field>
139
+ );
140
+ }}
141
+ />
142
+ </FieldGroup>
143
+ </form>
144
+ </CardContent>
145
+ <CardFooter>
146
+ <div className="w-full">
147
+ <Field orientation="horizontal">
148
+ <Button
149
+ type="submit"
150
+ form="form-login"
151
+ className="w-full"
152
+ disabled={isLoading}
153
+ >
154
+ {isLoading ? "Resetting..." : "Reset Password"}
155
+ </Button>
156
+ </Field>
157
+ </div>
158
+ </CardFooter>
159
+ </Card>
160
+ );
161
+ };
162
+
163
+ export default ResetComponent;