user forms added
This commit is contained in:
90
frontend/src/routes/(auth)/-components/ChangePassword.tsx
Normal file
90
frontend/src/routes/(auth)/-components/ChangePassword.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import { useRouter } from "@tanstack/react-router";
|
||||
import { toast } from "sonner";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
import { useAppForm } from "@/lib/formSutff";
|
||||
|
||||
export default function ChangePassword() {
|
||||
const router = useRouter();
|
||||
const form = useAppForm({
|
||||
defaultValues: {
|
||||
currentPassword: "",
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
if (value.newPassword !== value.confirmPassword) {
|
||||
toast.error("Passwords do not match");
|
||||
return;
|
||||
}
|
||||
const { data, error } = await authClient.changePassword({
|
||||
newPassword: value.newPassword,
|
||||
currentPassword: value.currentPassword,
|
||||
revokeOtherSessions: true,
|
||||
});
|
||||
|
||||
if (data) {
|
||||
toast.success("Password has been updated");
|
||||
form.reset();
|
||||
router.invalidate();
|
||||
|
||||
//navigate({ to: "/login" });
|
||||
}
|
||||
|
||||
if (error) {
|
||||
toast.success(error.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
return (
|
||||
<div>
|
||||
<Card className="p-6 w-96">
|
||||
<CardHeader>
|
||||
<CardTitle>Change password</CardTitle>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
form.handleSubmit();
|
||||
}}
|
||||
>
|
||||
<form.AppField name="currentPassword">
|
||||
{(field) => (
|
||||
<field.InputPasswordField
|
||||
label="Enter your current password"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
</form.AppField>
|
||||
|
||||
<form.AppField name="newPassword">
|
||||
{(field) => (
|
||||
<field.InputPasswordField
|
||||
label="New password"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
</form.AppField>
|
||||
|
||||
<form.AppField name="confirmPassword">
|
||||
{(field) => (
|
||||
<field.InputPasswordField
|
||||
label="Re-enter your password"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
</form.AppField>
|
||||
|
||||
<div className="flex justify-end mt-6">
|
||||
<form.AppForm>
|
||||
<form.SubmitButton>Update Profile</form.SubmitButton>
|
||||
</form.AppForm>
|
||||
</div>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
|
||||
76
frontend/src/routes/(auth)/-components/ResetForm.tsx
Normal file
76
frontend/src/routes/(auth)/-components/ResetForm.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
import { useAppForm } from "@/lib/formSutff";
|
||||
|
||||
export default function ResetForm() {
|
||||
const form = useAppForm({
|
||||
defaultValues: {
|
||||
email: "",
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
const { data, error } = await authClient.requestPasswordReset({
|
||||
email: value.email,
|
||||
redirectTo: `${window.location.origin}`,
|
||||
});
|
||||
|
||||
if (data) {
|
||||
toast.success(data.message);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
toast.error(error.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="flex justify-center mt-2">
|
||||
<Card className="p-6 w-96">
|
||||
<CardHeader>
|
||||
<CardTitle>Reset your password</CardTitle>
|
||||
<CardDescription>
|
||||
Enter your email address and we’ll send you a reset link
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
form.handleSubmit();
|
||||
}}
|
||||
>
|
||||
<form.AppField name="email">
|
||||
{(field) => (
|
||||
<field.InputField label="Email" inputType="email" required />
|
||||
)}
|
||||
</form.AppField>
|
||||
|
||||
<div className="flex justify-end mt-6">
|
||||
<form.AppForm>
|
||||
<form.SubmitButton>Send Reset Link</form.SubmitButton>
|
||||
</form.AppForm>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div className="mt-6 text-center text-sm text-gray-600">
|
||||
Remembered your password?{" "}
|
||||
<Link
|
||||
to="/login"
|
||||
className="text-primary underline underline-offset-4 hover:text-primary/80"
|
||||
>
|
||||
Back to login
|
||||
</Link>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
94
frontend/src/routes/(auth)/-components/ResetPassword.tsx
Normal file
94
frontend/src/routes/(auth)/-components/ResetPassword.tsx
Normal file
@@ -0,0 +1,94 @@
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import React from "react";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
import { useAppForm } from "@/lib/formSutff";
|
||||
|
||||
export default function ResetPassword({ token }: { token: string }) {
|
||||
const form = useAppForm({
|
||||
defaultValues: {
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
if (!token) {
|
||||
toast.error("No token was included");
|
||||
return;
|
||||
}
|
||||
|
||||
const { data, error } = await authClient.resetPassword({
|
||||
newPassword: value.password,
|
||||
token,
|
||||
});
|
||||
|
||||
if (data) {
|
||||
toast.success("Password has been reset");
|
||||
}
|
||||
|
||||
if (error) {
|
||||
toast.error(error.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="flex justify-center mt-2">
|
||||
<Card className="p-6 w-96">
|
||||
<CardHeader>
|
||||
<CardTitle>Reset your password</CardTitle>
|
||||
<CardDescription>
|
||||
Enter your email address and we’ll send you a reset link
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
form.handleSubmit();
|
||||
}}
|
||||
>
|
||||
<form.AppField name="password">
|
||||
{(field) => (
|
||||
<field.InputPasswordField
|
||||
label="New Password"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
</form.AppField>
|
||||
<form.AppField name="confirmPassword">
|
||||
{(field) => (
|
||||
<field.InputPasswordField
|
||||
label="Confirm Password"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
</form.AppField>
|
||||
|
||||
<div className="flex justify-end mt-6">
|
||||
<form.AppForm>
|
||||
<form.SubmitButton>Send Reset Link</form.SubmitButton>
|
||||
</form.AppForm>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div className="mt-6 text-center text-sm text-gray-600">
|
||||
Remembered your password?{" "}
|
||||
<Link
|
||||
to="/login"
|
||||
className="text-primary underline underline-offset-4 hover:text-primary/80"
|
||||
>
|
||||
Back to login
|
||||
</Link>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
99
frontend/src/routes/(auth)/user.profile.tsx
Normal file
99
frontend/src/routes/(auth)/user.profile.tsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import { createFileRoute, redirect, useRouter } from "@tanstack/react-router";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { authClient, useSession } from "@/lib/auth-client";
|
||||
import { useAppForm } from "@/lib/formSutff";
|
||||
import ChangePassword from "./-components/ChangePassword";
|
||||
|
||||
export const Route = createFileRoute("/(auth)/user/profile")({
|
||||
beforeLoad: async () => {
|
||||
const result = await authClient.getSession({
|
||||
query: { disableCookieCache: true }, // force DB/Server lookup
|
||||
});
|
||||
|
||||
//console.log("session check:", result.data);
|
||||
|
||||
if (!result.data) {
|
||||
throw redirect({
|
||||
to: "/login",
|
||||
search: {
|
||||
redirect: location.pathname + location.search,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
const { data: session } = useSession();
|
||||
const router = useRouter();
|
||||
const form = useAppForm({
|
||||
defaultValues: {
|
||||
name: session?.user.name,
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
const { data, error } = await authClient.updateUser({
|
||||
name: value.name,
|
||||
});
|
||||
|
||||
if (data) {
|
||||
toast.success("Profile has been updated");
|
||||
form.reset();
|
||||
//navigate({ to: "/login" });
|
||||
}
|
||||
|
||||
if (error) {
|
||||
toast.success(error.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
return (
|
||||
<div className="flex justify-center mt-2 gap-2">
|
||||
<div>
|
||||
<Card className="p-6 w-96">
|
||||
<CardHeader>
|
||||
<CardTitle>Profile</CardTitle>
|
||||
<CardDescription>
|
||||
Change your profile and password below
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
form.handleSubmit();
|
||||
}}
|
||||
>
|
||||
<form.AppField name="name">
|
||||
{(field) => (
|
||||
<field.InputField
|
||||
label="Name"
|
||||
inputType="string"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
</form.AppField>
|
||||
|
||||
<div className="flex justify-end mt-6">
|
||||
<form.AppForm>
|
||||
<form.SubmitButton>Update Profile</form.SubmitButton>
|
||||
</form.AppForm>
|
||||
</div>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div>
|
||||
<ChangePassword />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,31 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import { createFileRoute, Link } from "@tanstack/react-router";
|
||||
import { toast } from "sonner";
|
||||
import z from "zod";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
import { useAppForm } from "@/lib/formSutff";
|
||||
import ResetForm from "./-components/ResetForm";
|
||||
import ResetPassword from "./-components/ResetPassword";
|
||||
|
||||
export const Route = createFileRoute('/(auth)/user/resetpassword')({
|
||||
component: RouteComponent,
|
||||
})
|
||||
export const Route = createFileRoute("/(auth)/user/resetpassword")({
|
||||
validateSearch: z.object({
|
||||
token: z.string().optional(),
|
||||
}),
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
return <div>Hello "/(auth)/user/resetpassword"!</div>
|
||||
const { token } = Route.useSearch();
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
{token ? <ResetPassword token={token} /> : <ResetForm />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,128 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import { createFileRoute, Link, useNavigate } from "@tanstack/react-router";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
import { useAppForm } from "@/lib/formSutff";
|
||||
|
||||
export const Route = createFileRoute('/(auth)/user/signup')({
|
||||
component: RouteComponent,
|
||||
})
|
||||
export const Route = createFileRoute("/(auth)/user/signup")({
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
return <div>Hello "/(auth)/user/signup"!</div>
|
||||
const navigate = useNavigate();
|
||||
const form = useAppForm({
|
||||
defaultValues: {
|
||||
name: "",
|
||||
email: "",
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
if (value.password !== value.confirmPassword) {
|
||||
toast.error("Passwords do not match");
|
||||
return;
|
||||
}
|
||||
|
||||
const { data, error } = await authClient.signUp.email({
|
||||
name: value.name,
|
||||
email: value.email,
|
||||
password: value.password,
|
||||
callbackURL: `${window.location.origin}/lst/app`,
|
||||
});
|
||||
|
||||
if (data) {
|
||||
toast.success(`Welcome ${value.name}, to lst.`);
|
||||
navigate({ to: "/" });
|
||||
}
|
||||
|
||||
if (error) {
|
||||
toast.error(error.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
return (
|
||||
<div className="flex justify-center mt-2">
|
||||
<Card className="p-6 w-96">
|
||||
<CardHeader>
|
||||
<CardTitle>Create an account</CardTitle>
|
||||
<CardDescription>Fill in your details to get started</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
form.handleSubmit();
|
||||
}}
|
||||
>
|
||||
{/* Username */}
|
||||
<form.AppField name="name">
|
||||
{(field) => (
|
||||
<field.InputField
|
||||
label="Name"
|
||||
inputType="text"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
</form.AppField>
|
||||
|
||||
{/* Email */}
|
||||
<form.AppField name="email">
|
||||
{(field) => (
|
||||
<field.InputField
|
||||
label="Email address"
|
||||
inputType="email"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
</form.AppField>
|
||||
|
||||
{/* Password */}
|
||||
<form.AppField name="password">
|
||||
{(field) => (
|
||||
<field.InputField
|
||||
label="Password"
|
||||
inputType="password"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
</form.AppField>
|
||||
|
||||
{/* Confirm Password */}
|
||||
<form.AppField name="confirmPassword">
|
||||
{(field) => (
|
||||
<field.InputField
|
||||
label="Confirm Password"
|
||||
inputType="password"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
</form.AppField>
|
||||
|
||||
<div className="flex justify-end mt-6">
|
||||
<form.AppForm>
|
||||
<form.SubmitButton>Sign Up</form.SubmitButton>
|
||||
</form.AppForm>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div className="mt-6 text-center text-sm text-gray-600">
|
||||
Already have an account?{" "}
|
||||
<Link
|
||||
to={"/login"}
|
||||
className="text-primary underline underline-offset-4 hover:text-primary/80"
|
||||
>
|
||||
Log in
|
||||
</Link>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
import z from "zod";
|
||||
|
||||
import { useSession } from "../lib/auth-client";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { authClient, useSession } from "../lib/auth-client";
|
||||
|
||||
export const Route = createFileRoute("/")({
|
||||
validateSearch: z.object({
|
||||
@@ -13,11 +13,12 @@ export const Route = createFileRoute("/")({
|
||||
});
|
||||
|
||||
function Index() {
|
||||
const { data: session, isPending } = useSession();
|
||||
const { isPending } = useSession();
|
||||
|
||||
if (isPending)
|
||||
return <div className="flex justify-center mt-10">Loading...</div>;
|
||||
// if (!session) return <button>Sign In</button>
|
||||
|
||||
return (
|
||||
<div className="flex justify-center mt-10">
|
||||
<h3 className="w-2xl text-3xl">Welcome Home!</h3>
|
||||
|
||||
Reference in New Issue
Block a user