feat(admin): Server Action'larla kullanıcı yönetimi ve gerçek oturumlu sayfalar
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,8 @@ import { Button } from "@/components/ui/button";
|
||||
import { Field, FieldError, FieldGroup, FieldLabel } from "@/components/ui/field";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { tr } from "@/i18n/tr";
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
import { looksLikeEmail, normalizeUsername } from "@/shared/schemas/common";
|
||||
import { loginSchema, type LoginInput } from "@/shared/schemas/auth";
|
||||
|
||||
export function LoginForm() {
|
||||
@@ -20,11 +22,23 @@ export function LoginForm() {
|
||||
defaultValues: { identifier: "", password: "" },
|
||||
});
|
||||
|
||||
async function onSubmit(_values: LoginInput) {
|
||||
async function onSubmit({ identifier, password }: LoginInput) {
|
||||
setFormError(null);
|
||||
// FAZ 3: looksLikeEmail(identifier) ? authClient.signIn.email : authClient.signIn.username
|
||||
await new Promise((r) => setTimeout(r, 400));
|
||||
const value = identifier.trim();
|
||||
const { error } = looksLikeEmail(value)
|
||||
? await authClient.signIn.email({ email: value.toLowerCase(), password })
|
||||
: await authClient.signIn.username({ username: normalizeUsername(value), password });
|
||||
|
||||
if (error) {
|
||||
// Hangi bilginin yanlış olduğu söylenmez (hesap tahmini zorlaşır).
|
||||
if (error.status === 429) setFormError(tr.auth.tooManyAttempts);
|
||||
else if (error.code === "BANNED_USER") setFormError(tr.auth.banned);
|
||||
else setFormError(tr.auth.invalidCredentials);
|
||||
form.setValue("password", "");
|
||||
return;
|
||||
}
|
||||
router.replace("/dashboard");
|
||||
router.refresh();
|
||||
}
|
||||
|
||||
const submitting = form.formState.isSubmitting;
|
||||
|
||||
@@ -1,14 +1,27 @@
|
||||
import type { Metadata } from "next";
|
||||
import { redirect } from "next/navigation";
|
||||
import { Suspense } from "react";
|
||||
import { Logo } from "@/components/brand/logo";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { tr } from "@/i18n/tr";
|
||||
import { getCurrentUser } from "@/lib/dal";
|
||||
import { LoginForm } from "./login-form";
|
||||
|
||||
export const metadata: Metadata = { title: tr.auth.loginTitle };
|
||||
|
||||
/** Oturum açıksa dashboard'a yönlendirir (istek anında, Suspense içinde). */
|
||||
async function RedirectIfSignedIn() {
|
||||
const user = await getCurrentUser();
|
||||
if (user) redirect("/dashboard");
|
||||
return null;
|
||||
}
|
||||
|
||||
export default function LoginPage() {
|
||||
return (
|
||||
<main className="flex w-full max-w-sm flex-col items-center gap-6">
|
||||
<Suspense fallback={null}>
|
||||
<RedirectIfSignedIn />
|
||||
</Suspense>
|
||||
<Logo priority className="scale-125" />
|
||||
<Card className="w-full">
|
||||
<CardHeader>
|
||||
|
||||
Reference in New Issue
Block a user