Start working on the profile refactoring.

This commit is contained in:
charlesgauthereau
2025-12-21 16:55:12 +01:00
parent 428782e8a4
commit 116229a29e
77 changed files with 5076 additions and 509 deletions
+20 -12
View File
@@ -1,15 +1,23 @@
import {PageParams} from "@/types/next";
import {Metadata} from "next";
import {ForgotPasswordForm} from "@/components/wrappers/auth/forgot-password/forgot-password-form";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
export const metadata: Metadata = {
title: "Forgot Password",
};
import { TooltipProvider } from "@/components/ui/tooltip";
import { ForgotPasswordForm } from "@/components/wrappers/auth/login/forgot-password-form/forgot-password-form";
export default async function RoutePage(props: { searchParams: Promise<{ callbackUrl: string | undefined }> }) {
export default async function RoutePage(props: PageParams<{}>) {
return (
<div className="mx-auto grid w-full gap-6">
<ForgotPasswordForm/>
</div>
)
}
<TooltipProvider>
<Card className="w-full">
<CardHeader>
<div className="grid gap-2 text-center mb-2">
<h1 className="text-3xl font-bold">Reset password</h1>
<p className="text-balance text-muted-foreground">Enter your email address and we'll send you a link to reset your password.</p>
</div>
</CardHeader>
<CardContent>
<ForgotPasswordForm />
</CardContent>
</Card>
</TooltipProvider>
);
}
+32
View File
@@ -0,0 +1,32 @@
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { TooltipProvider } from "@/components/ui/tooltip";
import { GuardForm } from "@/components/wrappers/auth/guard/guard-form";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";
export default async function GuardPage() {
const cookieStore = await cookies();
const token = cookieStore.get("better-auth.two_factor")?.value;
if (!token) {
redirect("/login");
}
return (
<TooltipProvider>
<Card className="w-full max-w-md">
<CardHeader>
<div className="grid gap-2 text-center mb-2">
<h1 className="text-3xl font-bold">Two-factor verification</h1>
<p className="text-balance text-muted-foreground">Please enter the verification code generated by your authentication app.</p>
</div>
</CardHeader>
<CardContent>
<GuardForm />
</CardContent>
</Card>
</TooltipProvider>
);
}
+43 -5
View File
@@ -1,17 +1,55 @@
import {env} from "@/env.mjs";
import {LoginForm} from "@/components/wrappers/auth/login/login-form/login-form";
import {Metadata} from "next";
import {SUPPORTED_PROVIDERS} from "../../../portabase.config";
import {SocialAuthButtons} from "@/components/wrappers/auth/social-buttons";
import {TooltipProvider} from "@/components/ui/tooltip";
import {Card, CardContent, CardHeader} from "@/components/ui/card";
import Link from "next/link";
import {Separator} from "@/components/ui/separator";
export const metadata: Metadata = {
title: "Login",
};
export default async function SignInPage() {
const authGoogleEnabled = env.AUTH_GOOGLE_METHOD;
return (
<div className="mx-auto grid w-full gap-6">
<LoginForm authGoogleEnabled={authGoogleEnabled}/>
</div>
<TooltipProvider>
<Card className="w-full">
<CardHeader>
<div className="grid gap-2 text-center mb-2">
<h1 className="text-3xl font-bold">Login</h1>
<p className="text-balance text-muted-foreground">Fill your login informations</p>
</div>
</CardHeader>
<CardContent className="space-y-4">
<LoginForm />
{SUPPORTED_PROVIDERS.filter((p) => !p.isManual).length > 0 && (
<>
<div className="relative my-4 flex items-center justify-center overflow-hidden">
<Separator/>
<div className="px-2 text-center bg-card text-sm">OR</div>
<Separator/>
</div>
<SocialAuthButtons />
</>
)}
<div className="mt-4 text-center text-sm">
Don&apos;t have an account ?{" "}
<Link href="/register" className="underline">
Sign up
</Link>
</div>
</CardContent>
</Card>
</TooltipProvider>
)
}
-62
View File
@@ -1,62 +0,0 @@
import {PageParams} from "@/types/next";
import {Page, PageContent, PageTitle} from "@/features/layout/page";
import {notFound} from "next/navigation";
import {UserForm} from "@/components/wrappers/dashboard/profile/user-form/user-form";
import {Badge} from "@/components/ui/badge";
import {AvatarWithUpload} from "@/components/wrappers/dashboard/profile/avatar/avatar-with-upload";
import {currentUser} from "@/lib/auth/current-user";
import {getAccounts, getSessions} from "@/lib/auth/auth";
import {Metadata} from "next";
export const metadata: Metadata = {
title: "Profile",
};
export default async function RoutePage(props: PageParams<{}>) {
const user = await currentUser();
if (!user) {
return notFound();
}
if (user.role !== "user" && user.role !== "admin" && user.role !== "superadmin") {
return notFound();
}
const sessions = await getSessions();
const accounts = await getAccounts();
return (
<Page>
<div className="justify-between gap-2 sm:flex">
<PageTitle className="flex items-center">
<AvatarWithUpload
user={{
...user,
image: user.image ?? null,
role: user.role ?? null,
banned: user.banned ?? null,
banReason: user.banReason ?? null,
banExpires: user.banExpires ?? null,
deletedAt: user.deletedAt ? new Date(user.deletedAt) : null,
}}
/>
{user.name}
<Badge className="ml-3 hidden lg:block">{user.role}</Badge>
</PageTitle>
</div>
<PageContent>
<UserForm
userId={user.id}
sessions={sessions}
accounts={accounts}
defaultValues={{
name: user.name,
email: user.email,
role: user.role ?? undefined,
}}
/>
</PageContent>
</Page>
);
}
+1 -1
View File
@@ -7,7 +7,7 @@ import {Database} from "@/db/schema/07_database";
import * as drizzleDb from "@/db";
import {db as dbClient} from "@/db";
import {and, eq} from "drizzle-orm";
import {dbmsEnumSchema, EDbmsSchema} from "@/db/schema/types";
import {EDbmsSchema} from "@/db/schema/types";
import {ServerActionResult} from "@/types/action-type";
import {SafeActionResult} from "next-safe-action";
import {ZodString} from "zod";