feat(auth): signupm, forgot passowrd, reset password all added
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { Server, Settings, User, type LucideIcon } from "lucide-react";
|
||||
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
|
||||
import { userAccess, type UserRoles } from "../../lib/authClient";
|
||||
import {
|
||||
SidebarGroup,
|
||||
@@ -65,6 +66,10 @@ export default function Admin() {
|
||||
</>
|
||||
</SidebarMenuItem>
|
||||
))}
|
||||
|
||||
{userAccess(null, ["systemAdmin"]) && (
|
||||
<TanStackRouterDevtools position="bottom-right" />
|
||||
)}
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
|
||||
@@ -21,16 +21,17 @@ export default function Nav() {
|
||||
<div className="m-1">
|
||||
<ModeToggle />
|
||||
</div>
|
||||
{/* <div className="mr-1 ml-1">
|
||||
{settings.length > 0 && (
|
||||
<div className="m-1">
|
||||
<Button>
|
||||
<a
|
||||
href={`https://${server[0].value}.alpla.net/lst/d`}
|
||||
href={`${window.location.origin}/lst/d`}
|
||||
target="_blank"
|
||||
>
|
||||
LST - Docs |
|
||||
LST - Docs
|
||||
</a>
|
||||
)}
|
||||
</div> */}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{session ? (
|
||||
<div className="m-1">
|
||||
<DropdownMenu>
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { Sidebar, SidebarFooter, SidebarTrigger } from "../ui/sidebar";
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarFooter,
|
||||
SidebarTrigger,
|
||||
} from "../ui/sidebar";
|
||||
import { Header } from "./Header";
|
||||
import Admin from "./Admin";
|
||||
import { userAccess } from "../../lib/authClient";
|
||||
@@ -8,7 +13,9 @@ export default function SideBarNav() {
|
||||
<div className="flex min-h-screen">
|
||||
<Sidebar collapsible="icon">
|
||||
<Header />
|
||||
{userAccess(null, ["systemAdmin", "admin"]) && <Admin />}
|
||||
<SidebarContent>
|
||||
{userAccess(null, ["systemAdmin", "admin"]) && <Admin />}
|
||||
</SidebarContent>
|
||||
|
||||
<SidebarFooter>
|
||||
<SidebarTrigger />
|
||||
|
||||
52
frontend/src/lib/formStuff/components/InputPasswordField.tsx
Normal file
52
frontend/src/lib/formStuff/components/InputPasswordField.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { useState } from "react";
|
||||
import { useFieldContext } from "..";
|
||||
import { FieldErrors } from "./FieldErrors";
|
||||
import { Eye, EyeOff } from "lucide-react";
|
||||
import { Label } from "../../../components/ui/label";
|
||||
import { Input } from "../../../components/ui/input";
|
||||
import { Button } from "../../../components/ui/button";
|
||||
|
||||
type PasswordInputProps = {
|
||||
label: string;
|
||||
required?: boolean;
|
||||
};
|
||||
|
||||
export const InputPasswordField = ({
|
||||
label,
|
||||
required = false,
|
||||
}: PasswordInputProps) => {
|
||||
const field = useFieldContext<any>();
|
||||
const [show, setShow] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="grid gap-3">
|
||||
<Label htmlFor={field.name}>{label}</Label>
|
||||
<div className="relative">
|
||||
<Input
|
||||
id={field.name}
|
||||
type={show ? "text" : "password"}
|
||||
value={field.state.value}
|
||||
onChange={(e) => field.handleChange(e.target.value)}
|
||||
onBlur={field.handleBlur}
|
||||
required={required}
|
||||
className="pr-10"
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setShow((p) => !p)}
|
||||
className="absolute right-1 top-1/2 -translate-y-1/2 h-7 w-7"
|
||||
tabIndex={-1} // prevent messing with tab order
|
||||
>
|
||||
{show ? (
|
||||
<EyeOff className="h-4 w-4" />
|
||||
) : (
|
||||
<Eye className="h-4 w-4" />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
<FieldErrors meta={field.state.meta} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -3,12 +3,18 @@ import { SubmitButton } from "./components/SubmitButton";
|
||||
import { InputField } from "./components/InputField";
|
||||
import { SelectField } from "./components/SelectField";
|
||||
import { CheckboxField } from "./components/CheckBox";
|
||||
import { InputPasswordField } from "./components/InputPasswordField";
|
||||
|
||||
export const { fieldContext, useFieldContext, formContext, useFormContext } =
|
||||
createFormHookContexts();
|
||||
|
||||
export const { useAppForm } = createFormHook({
|
||||
fieldComponents: { InputField, SelectField, CheckboxField },
|
||||
fieldComponents: {
|
||||
InputField,
|
||||
InputPasswordField,
|
||||
SelectField,
|
||||
CheckboxField,
|
||||
},
|
||||
formComponents: { SubmitButton },
|
||||
fieldContext,
|
||||
formContext,
|
||||
|
||||
@@ -15,6 +15,8 @@ import { Route as authLoginRouteImport } from './routes/(auth)/login'
|
||||
import { Route as AdminLayoutAdminUsersRouteImport } from './routes/_adminLayout/admin/users'
|
||||
import { Route as AdminLayoutAdminSettingsRouteImport } from './routes/_adminLayout/admin/settings'
|
||||
import { Route as AdminLayoutAdminServersRouteImport } from './routes/_adminLayout/admin/servers'
|
||||
import { Route as authUserSignupRouteImport } from './routes/(auth)/user/signup'
|
||||
import { Route as authUserResetpasswordRouteImport } from './routes/(auth)/user/resetpassword'
|
||||
|
||||
const AdminLayoutRouteRoute = AdminLayoutRouteRouteImport.update({
|
||||
id: '/_adminLayout',
|
||||
@@ -46,10 +48,22 @@ const AdminLayoutAdminServersRoute = AdminLayoutAdminServersRouteImport.update({
|
||||
path: '/admin/servers',
|
||||
getParentRoute: () => AdminLayoutRouteRoute,
|
||||
} as any)
|
||||
const authUserSignupRoute = authUserSignupRouteImport.update({
|
||||
id: '/(auth)/user/signup',
|
||||
path: '/user/signup',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const authUserResetpasswordRoute = authUserResetpasswordRouteImport.update({
|
||||
id: '/(auth)/user/resetpassword',
|
||||
path: '/user/resetpassword',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
|
||||
export interface FileRoutesByFullPath {
|
||||
'/': typeof IndexRoute
|
||||
'/login': typeof authLoginRoute
|
||||
'/user/resetpassword': typeof authUserResetpasswordRoute
|
||||
'/user/signup': typeof authUserSignupRoute
|
||||
'/admin/servers': typeof AdminLayoutAdminServersRoute
|
||||
'/admin/settings': typeof AdminLayoutAdminSettingsRoute
|
||||
'/admin/users': typeof AdminLayoutAdminUsersRoute
|
||||
@@ -57,6 +71,8 @@ export interface FileRoutesByFullPath {
|
||||
export interface FileRoutesByTo {
|
||||
'/': typeof IndexRoute
|
||||
'/login': typeof authLoginRoute
|
||||
'/user/resetpassword': typeof authUserResetpasswordRoute
|
||||
'/user/signup': typeof authUserSignupRoute
|
||||
'/admin/servers': typeof AdminLayoutAdminServersRoute
|
||||
'/admin/settings': typeof AdminLayoutAdminSettingsRoute
|
||||
'/admin/users': typeof AdminLayoutAdminUsersRoute
|
||||
@@ -66,6 +82,8 @@ export interface FileRoutesById {
|
||||
'/': typeof IndexRoute
|
||||
'/_adminLayout': typeof AdminLayoutRouteRouteWithChildren
|
||||
'/(auth)/login': typeof authLoginRoute
|
||||
'/(auth)/user/resetpassword': typeof authUserResetpasswordRoute
|
||||
'/(auth)/user/signup': typeof authUserSignupRoute
|
||||
'/_adminLayout/admin/servers': typeof AdminLayoutAdminServersRoute
|
||||
'/_adminLayout/admin/settings': typeof AdminLayoutAdminSettingsRoute
|
||||
'/_adminLayout/admin/users': typeof AdminLayoutAdminUsersRoute
|
||||
@@ -75,16 +93,27 @@ export interface FileRouteTypes {
|
||||
fullPaths:
|
||||
| '/'
|
||||
| '/login'
|
||||
| '/user/resetpassword'
|
||||
| '/user/signup'
|
||||
| '/admin/servers'
|
||||
| '/admin/settings'
|
||||
| '/admin/users'
|
||||
fileRoutesByTo: FileRoutesByTo
|
||||
to: '/' | '/login' | '/admin/servers' | '/admin/settings' | '/admin/users'
|
||||
to:
|
||||
| '/'
|
||||
| '/login'
|
||||
| '/user/resetpassword'
|
||||
| '/user/signup'
|
||||
| '/admin/servers'
|
||||
| '/admin/settings'
|
||||
| '/admin/users'
|
||||
id:
|
||||
| '__root__'
|
||||
| '/'
|
||||
| '/_adminLayout'
|
||||
| '/(auth)/login'
|
||||
| '/(auth)/user/resetpassword'
|
||||
| '/(auth)/user/signup'
|
||||
| '/_adminLayout/admin/servers'
|
||||
| '/_adminLayout/admin/settings'
|
||||
| '/_adminLayout/admin/users'
|
||||
@@ -94,6 +123,8 @@ export interface RootRouteChildren {
|
||||
IndexRoute: typeof IndexRoute
|
||||
AdminLayoutRouteRoute: typeof AdminLayoutRouteRouteWithChildren
|
||||
authLoginRoute: typeof authLoginRoute
|
||||
authUserResetpasswordRoute: typeof authUserResetpasswordRoute
|
||||
authUserSignupRoute: typeof authUserSignupRoute
|
||||
}
|
||||
|
||||
declare module '@tanstack/react-router' {
|
||||
@@ -140,6 +171,20 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof AdminLayoutAdminServersRouteImport
|
||||
parentRoute: typeof AdminLayoutRouteRoute
|
||||
}
|
||||
'/(auth)/user/signup': {
|
||||
id: '/(auth)/user/signup'
|
||||
path: '/user/signup'
|
||||
fullPath: '/user/signup'
|
||||
preLoaderRoute: typeof authUserSignupRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/(auth)/user/resetpassword': {
|
||||
id: '/(auth)/user/resetpassword'
|
||||
path: '/user/resetpassword'
|
||||
fullPath: '/user/resetpassword'
|
||||
preLoaderRoute: typeof authUserResetpasswordRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,6 +207,8 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
IndexRoute: IndexRoute,
|
||||
AdminLayoutRouteRoute: AdminLayoutRouteRouteWithChildren,
|
||||
authLoginRoute: authLoginRoute,
|
||||
authUserResetpasswordRoute: authUserResetpasswordRoute,
|
||||
authUserSignupRoute: authUserSignupRoute,
|
||||
}
|
||||
export const routeTree = rootRouteImport
|
||||
._addFileChildren(rootRouteChildren)
|
||||
|
||||
@@ -46,6 +46,7 @@ export default function LoginForm() {
|
||||
|
||||
const session = await getSession();
|
||||
setSession(session);
|
||||
form.reset();
|
||||
fetchRoles();
|
||||
|
||||
toast.success(
|
||||
@@ -54,12 +55,13 @@ export default function LoginForm() {
|
||||
router.invalidate();
|
||||
router.history.push(search.redirect ? search.redirect : "/");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
// @ts-ignore
|
||||
toast.error(error?.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
return (
|
||||
<div className="ml-[25%]">
|
||||
<div className="">
|
||||
<LstCard className="p-3 w-96">
|
||||
<CardHeader>
|
||||
<CardTitle>Login to your account</CardTitle>
|
||||
@@ -87,9 +89,8 @@ export default function LoginForm() {
|
||||
<form.AppField
|
||||
name="password"
|
||||
children={(field) => (
|
||||
<field.InputField
|
||||
<field.InputPasswordField
|
||||
label="Password"
|
||||
inputType="password"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
@@ -102,7 +103,7 @@ export default function LoginForm() {
|
||||
)}
|
||||
/>
|
||||
<Link
|
||||
to="/"
|
||||
to="/user/resetpassword"
|
||||
className="inline-block text-sm underline-offset-4 hover:underline"
|
||||
>
|
||||
Forgot your password?
|
||||
@@ -118,9 +119,12 @@ export default function LoginForm() {
|
||||
|
||||
<div className="mt-4 text-center text-sm">
|
||||
Don't have an account?{" "}
|
||||
<a href="#" className="underline underline-offset-4">
|
||||
<Link
|
||||
to={"/user/signup"}
|
||||
className="underline underline-offset-4"
|
||||
>
|
||||
Sign up
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</CardContent>
|
||||
</LstCard>
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import { LstCard } from "../../../components/ui/lstCard";
|
||||
import {
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "../../../components/ui/card";
|
||||
import { useAppForm } from "../../../lib/formStuff";
|
||||
import { api } from "../../../lib/axiosAPI";
|
||||
import { toast } from "sonner";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
|
||||
export default function RequestResetPassword() {
|
||||
const form = useAppForm({
|
||||
defaultValues: {
|
||||
email: "",
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
try {
|
||||
const res = await api.post("api/user/resetpassword", {
|
||||
email: value.email,
|
||||
});
|
||||
|
||||
console.log(res);
|
||||
|
||||
if (res.status === 200) {
|
||||
toast.success(
|
||||
res.data.message
|
||||
? res.data.message
|
||||
: "If this email exists in our system, check your email for the reset link"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<LstCard 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"
|
||||
children={(field) => (
|
||||
<field.InputField
|
||||
label="Email address"
|
||||
inputType="email"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<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>
|
||||
</LstCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
114
frontend/src/routes/(auth)/-components/ResetPasswordForm.tsx
Normal file
114
frontend/src/routes/(auth)/-components/ResetPasswordForm.tsx
Normal file
@@ -0,0 +1,114 @@
|
||||
import { useAppForm } from "../../../lib/formStuff";
|
||||
import { LstCard } from "../../../components/ui/lstCard";
|
||||
import {
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "../../../components/ui/card";
|
||||
import { api } from "../../../lib/axiosAPI";
|
||||
import { toast } from "sonner";
|
||||
import { Link, useNavigate } from "@tanstack/react-router";
|
||||
|
||||
export default function ResetPasswordForm({ token }: { token: string }) {
|
||||
const navigate = useNavigate();
|
||||
const form = useAppForm({
|
||||
defaultValues: {
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
if (value.password != value.confirmPassword) {
|
||||
toast.error("Passwords do not match");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await api.post("/api/auth/reset-password", {
|
||||
newPassword: value.password,
|
||||
token: token,
|
||||
});
|
||||
if (res.status === 200) {
|
||||
toast.success("Password has been reset");
|
||||
form.reset();
|
||||
navigate({ to: "/login" });
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
// @ts-ignore
|
||||
toast.error(error?.response.data.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<LstCard className="p-6 w-96">
|
||||
<CardHeader>
|
||||
<CardTitle>Set a new password</CardTitle>
|
||||
<CardDescription>
|
||||
Enter your new password below and confirm it to continue
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
form.handleSubmit();
|
||||
}}
|
||||
>
|
||||
<form.AppField
|
||||
name="password"
|
||||
children={(field) => (
|
||||
<field.InputPasswordField
|
||||
label="New Password"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<form.AppField
|
||||
name="confirmPassword"
|
||||
// validators={{
|
||||
// onChangeListenTo: ["password"],
|
||||
// onChange: ({ value, fieldApi }) => {
|
||||
// if (
|
||||
// value !==
|
||||
// fieldApi.form.getFieldValue("password")
|
||||
// ) {
|
||||
// return "Passwords do not match";
|
||||
// }
|
||||
// return undefined;
|
||||
// },
|
||||
// }}
|
||||
children={(field) => (
|
||||
<field.InputPasswordField
|
||||
label="Confirm Password"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end mt-6">
|
||||
<form.AppForm>
|
||||
<form.SubmitButton>
|
||||
Reset Password
|
||||
</form.SubmitButton>
|
||||
</form.AppForm>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div className="mt-6 text-center text-sm text-gray-600">
|
||||
Remembered your account?{" "}
|
||||
<Link
|
||||
to="/login"
|
||||
className="text-primary underline underline-offset-4 hover:text-primary/80"
|
||||
>
|
||||
Back to login
|
||||
</Link>
|
||||
</div>
|
||||
</CardContent>
|
||||
</LstCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
129
frontend/src/routes/(auth)/-components/SignupForm.tsx
Normal file
129
frontend/src/routes/(auth)/-components/SignupForm.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "../../../components/ui/card";
|
||||
import { LstCard } from "../../../components/ui/lstCard";
|
||||
import { api } from "../../../lib/axiosAPI";
|
||||
import { useAppForm } from "../../../lib/formStuff";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
|
||||
export default function SignupForm() {
|
||||
const form = useAppForm({
|
||||
defaultValues: {
|
||||
username: "",
|
||||
email: "",
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
if (value.password != value.confirmPassword) {
|
||||
toast.error("Passwords do not match");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await api.post("/api/user/register", {
|
||||
username: value.username,
|
||||
name: value.username,
|
||||
email: value.email,
|
||||
password: value.password,
|
||||
});
|
||||
|
||||
if (res.status === 200) {
|
||||
toast.success(`Welcome ${value.username}, to lst.`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
// @ts-ignore
|
||||
toast.error(error?.response.data.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
return (
|
||||
<div className="">
|
||||
<LstCard 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="username"
|
||||
children={(field) => (
|
||||
<field.InputField
|
||||
label="Username"
|
||||
inputType="text"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Email */}
|
||||
<form.AppField
|
||||
name="email"
|
||||
children={(field) => (
|
||||
<field.InputField
|
||||
label="Email address"
|
||||
inputType="email"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Password */}
|
||||
<form.AppField
|
||||
name="password"
|
||||
children={(field) => (
|
||||
<field.InputField
|
||||
label="Password"
|
||||
inputType="password"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Confirm Password */}
|
||||
<form.AppField
|
||||
name="confirmPassword"
|
||||
children={(field) => (
|
||||
<field.InputField
|
||||
label="Confirm Password"
|
||||
inputType="password"
|
||||
required={true}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<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>
|
||||
</LstCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -23,7 +23,7 @@ export const Route = createFileRoute("/(auth)/login")({
|
||||
|
||||
function RouteComponent() {
|
||||
return (
|
||||
<div className="m-[25%]">
|
||||
<div className="ml-[25%] mt-[0.5%]">
|
||||
<LoginForm />
|
||||
</div>
|
||||
);
|
||||
|
||||
27
frontend/src/routes/(auth)/user/resetpassword.tsx
Normal file
27
frontend/src/routes/(auth)/user/resetpassword.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import z from "zod";
|
||||
import RequestResetPassword from "../-components/RequestResetPassword";
|
||||
import ResetPasswordForm from "../-components/ResetPasswordForm";
|
||||
|
||||
export const Route = createFileRoute("/(auth)/user/resetpassword")({
|
||||
// beforeLoad: ({ search }) => {
|
||||
// return { token: search.token };
|
||||
// },
|
||||
validateSearch: z.object({
|
||||
token: z.string().optional(),
|
||||
}),
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
const { token } = Route.useSearch();
|
||||
return (
|
||||
<div className="ml-[25%] mt-[0.5%]">
|
||||
{token ? (
|
||||
<ResetPasswordForm token={token} />
|
||||
) : (
|
||||
<RequestResetPassword />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
14
frontend/src/routes/(auth)/user/signup.tsx
Normal file
14
frontend/src/routes/(auth)/user/signup.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import SignupForm from "../-components/SignupForm";
|
||||
|
||||
export const Route = createFileRoute("/(auth)/user/signup")({
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
return (
|
||||
<div className="ml-[25%] mt-[0.5%]">
|
||||
<SignupForm />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createRootRouteWithContext, Outlet } from "@tanstack/react-router";
|
||||
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
|
||||
|
||||
import type { QueryClient } from "@tanstack/react-query";
|
||||
import { Toaster } from "sonner";
|
||||
import Cookies from "js-cookie";
|
||||
@@ -18,7 +18,6 @@ interface RootRouteContext {
|
||||
|
||||
const RootLayout = () => {
|
||||
//const { logout, login } = Route.useRouteContext();
|
||||
|
||||
const defaultOpen = Cookies.get("sidebar_state") === "true";
|
||||
return (
|
||||
<div>
|
||||
@@ -26,16 +25,15 @@ const RootLayout = () => {
|
||||
<ThemeProvider>
|
||||
<div className="flex flex-col h-screen overflow-hidden">
|
||||
<Nav />
|
||||
<div className="flex flex-1 overflow-hidden">
|
||||
<div className="flex flex-1 overflow-hidden">
|
||||
<SidebarProvider defaultOpen={defaultOpen}>
|
||||
<SideBarNav />
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<div className="flex-2 overflow-y-auto">
|
||||
<Outlet />
|
||||
</div>
|
||||
</SidebarProvider>
|
||||
</div>
|
||||
<Toaster expand richColors closeButton />
|
||||
<TanStackRouterDevtools />
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
</SessionGuard>
|
||||
|
||||
@@ -1,25 +1,13 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { Button } from "../components/ui/button";
|
||||
import { useAuth } from "../lib/authClient";
|
||||
|
||||
export const Route = createFileRoute("/")({
|
||||
component: Index,
|
||||
});
|
||||
|
||||
function Index() {
|
||||
const { session } = useAuth();
|
||||
return (
|
||||
<div>
|
||||
<div className="h-screen flex flex-col items-center justify-center">
|
||||
<div>Welcome, {session ? session.user.username : "Guest"}</div>
|
||||
<div>
|
||||
<Button className="h-96 w-96">
|
||||
<a href="/lst/d" target="_blank" className="text-4xl">
|
||||
LST-DOCS
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-screen flex flex-col items-center justify-center"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user