user forms added

This commit is contained in:
2026-03-19 17:44:17 -05:00
parent 6b8d7b53d0
commit 85073c19d2
17 changed files with 576 additions and 70 deletions

View 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>
);
}

View File

@@ -4,7 +4,6 @@ import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";

View 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 well 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>
);
}

View 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 well 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>
);
}

View 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>
);
}

View File

@@ -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>
);
}

View File

@@ -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>
);
}

View File

@@ -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>