Files
alla-allaos-fullstack/src/features/auth/components/sign-in-view.tsx
2026-06-30 10:48:15 +07:00

172 lines
5.9 KiB
TypeScript

"use client";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { useAppForm } from "@/components/ui/tanstack-form";
import { cn } from "@/lib/utils";
import { getSession, signIn } from "next-auth/react";
import { useSearchParams } from "next/navigation";
import { useTransition } from "react";
import { toast } from "sonner";
import * as z from "zod";
import { InteractiveGridPattern } from "./interactive-grid";
const signInSchema = z.object({
email: z.string().email("Enter a valid email address"),
password: z.string().min(8, "Password must be at least 8 characters"),
});
export default function SignInViewPage() {
const searchParams = useSearchParams();
const callbackUrl = searchParams.get("callbackUrl") ?? "/dashboard/crm";
const [isPending, startTransition] = useTransition();
const form = useAppForm({
defaultValues: {
email: "",
password: "",
},
validators: {
onSubmit: signInSchema,
},
onSubmit: ({ value }) => {
startTransition(async () => {
const result = await signIn("credentials", {
email: value.email,
password: value.password,
redirect: false,
});
if (result?.error) {
toast.error("Invalid email or password");
return;
}
await getSession();
toast.success("Signed in successfully");
window.location.assign(callbackUrl);
});
},
});
return (
<div className="relative flex min-h-screen flex-col items-center justify-center overflow-hidden md:grid lg:max-w-none lg:grid-cols-2 lg:px-0">
<div className="relative hidden h-full flex-col p-10 lg:flex dark:border-r">
<div className="absolute inset-0 bg-sidebar" />
<div className="text-sidebar-foreground relative z-20 flex items-center text-lg font-medium">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="mr-2 h-6 w-6"
>
<path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3" />
</svg>
Auth.js Workspace Login
</div>
<InteractiveGridPattern
className={cn(
"mask-[radial-gradient(400px_circle_at_center,white,transparent)]",
"inset-x-0 inset-y-[0%] h-full skew-y-12",
)}
/>
<div className="text-sidebar-foreground relative z-20 mt-auto">
<blockquote className="space-y-2">
<p className="text-lg">
&ldquo;Move from template scaffolding to app-owned auth and data
without tearing up the dashboard UX.&rdquo;
</p>
<footer className="text-sidebar-foreground/70 text-sm">
Training System
</footer>
</blockquote>
</div>
</div>
<div className="flex h-full items-center justify-center p-4 lg:p-8">
<div className="flex w-full max-w-md flex-col items-center justify-center space-y-6">
<div className="w-full space-y-2 text-center">
<h1 className="text-2xl font-semibold tracking-tight">
Sign in to your workspace
</h1>
<p className="text-muted-foreground text-sm">
Use the credentials created for you by a super admin or
organization admin.
</p>
</div>
<form.AppForm>
<form.Form className="w-full space-y-4">
<form.AppField
name="email"
children={(field) => (
<field.FieldSet>
<field.Field>
<field.FieldLabel htmlFor={field.name}>
Email
</field.FieldLabel>
<Input
id={field.name}
name={field.name}
type="email"
value={field.state.value}
onBlur={field.handleBlur}
onChange={(event) =>
field.handleChange(event.target.value)
}
placeholder="you@example.com"
disabled={isPending}
/>
</field.Field>
<field.FieldError />
</field.FieldSet>
)}
/>
<form.AppField
name="password"
children={(field) => (
<field.FieldSet>
<field.Field>
<field.FieldLabel htmlFor={field.name}>
Password
</field.FieldLabel>
<Input
id={field.name}
name={field.name}
type="password"
value={field.state.value}
onBlur={field.handleBlur}
onChange={(event) =>
field.handleChange(event.target.value)
}
placeholder="Enter your password"
disabled={isPending}
/>
</field.Field>
<field.FieldError />
</field.FieldSet>
)}
/>
<Button className="w-full" type="submit" isLoading={isPending}>
Sign in
</Button>
</form.Form>
</form.AppForm>
<div className="text-muted-foreground space-y-2 px-8 text-center text-xs">
<p>
This starter now uses app-owned authentication with Auth.js and an
internal organization model.
</p>
</div>
</div>
</div>
</div>
);
}