mirror of
https://github.com/Nezumi-2711/multitenant-ecommerce.git
synced 2026-09-22 20:01:36 +00:00
Merge pull request #7 from Nezumi-2711/feat/auth-states
Feature/ Implement auth states
This commit is contained in:
@@ -1,7 +1,16 @@
|
||||
import { SignInView } from "@/modules/auth/ui/views/sign-in-view";
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
const Page = () => {
|
||||
return <SignInView />
|
||||
}
|
||||
import { caller } from '@/trpc/server';
|
||||
import { SignInView } from '@/modules/auth/ui/views/sign-in-view';
|
||||
|
||||
const Page = async () => {
|
||||
const session = await caller.auth.session();
|
||||
|
||||
if (session.user) {
|
||||
redirect('/');
|
||||
}
|
||||
|
||||
return <SignInView />;
|
||||
};
|
||||
|
||||
export default Page;
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
import { SignUpView } from "@/modules/auth/ui/views/sign-up-view";
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
const Page = () => {
|
||||
return <SignUpView />
|
||||
}
|
||||
import { caller } from '@/trpc/server';
|
||||
import { SignUpView } from '@/modules/auth/ui/views/sign-up-view';
|
||||
|
||||
const Page = async () => {
|
||||
const session = await caller.auth.session();
|
||||
|
||||
if (session.user) {
|
||||
redirect('/');
|
||||
}
|
||||
|
||||
return <SignUpView />;
|
||||
};
|
||||
|
||||
export default Page;
|
||||
|
||||
@@ -5,9 +5,11 @@ import Link from 'next/link';
|
||||
import { Poppins } from 'next/font/google';
|
||||
import { MenuIcon } from 'lucide-react';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useTRPC } from '@/trpc/client';
|
||||
|
||||
import NavbarSidebar from './navbar-sidebar';
|
||||
|
||||
@@ -64,9 +66,12 @@ const Navbar = () => {
|
||||
const pathname = usePathname();
|
||||
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<nav className="h-20 flex border-b justify-between font-medium bg-white">
|
||||
<Link href="/" className="pl-6 flex items-center">
|
||||
const trpc = useTRPC();
|
||||
const session = useQuery(trpc.auth.session.queryOptions());
|
||||
|
||||
return (
|
||||
<nav className="h-20 flex border-b justify-between font-medium bg-white">
|
||||
<Link href="/" className="pl-6 flex items-center">
|
||||
<span className={cn('text-5xl font-semibold', poppins.className)}>
|
||||
funroad
|
||||
</span>
|
||||
@@ -90,31 +95,53 @@ const Navbar = () => {
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="hidden lg:flex">
|
||||
<Button
|
||||
asChild
|
||||
variant="secondary"
|
||||
className="border-l border-t-0 border-b-0 border-r-0 px-12 h-full rounded-none bg-white hover:bg-pink-400 transition-colors text-lg"
|
||||
>
|
||||
<Link prefetch href="/sign-in">Log in</Link>
|
||||
</Button>
|
||||
{session.data?.user ? (
|
||||
<div className='hidden lg:flex'>
|
||||
<Button
|
||||
asChild
|
||||
variant="secondary"
|
||||
className="border-l border-t-0 border-b-0 border-r-0 px-12 h-full rounded-none bg-black text-white hover:bg-pink-400 hover:text-black transition-colors text-lg"
|
||||
>
|
||||
<Link href="/admin">
|
||||
Dashboard
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="hidden lg:flex">
|
||||
<Button
|
||||
asChild
|
||||
variant="secondary"
|
||||
className="border-l border-t-0 border-b-0 border-r-0 px-12 h-full rounded-none bg-white hover:bg-pink-400 transition-colors text-lg"
|
||||
>
|
||||
<Link prefetch href="/sign-in">
|
||||
Log in
|
||||
</Link>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
asChild
|
||||
variant="secondary"
|
||||
className="border-l border-t-0 border-b-0 border-r-0 px-12 h-full rounded-none bg-black text-white hover:bg-pink-400 hover:text-black transition-colors text-lg"
|
||||
>
|
||||
<Link prefetch href="/sign-up">Start Selling</Link>
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
asChild
|
||||
variant="secondary"
|
||||
className="border-l border-t-0 border-b-0 border-r-0 px-12 h-full rounded-none bg-black text-white hover:bg-pink-400 hover:text-black transition-colors text-lg"
|
||||
>
|
||||
<Link prefetch href="/sign-up">
|
||||
Start Selling
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className='flex lg:hidden items-center justify-center'>
|
||||
<Button variant="ghost" className="size-12 border-transparent bg-white" onClick={() => setIsSidebarOpen(true)}>
|
||||
<MenuIcon/>
|
||||
</Button>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
<div className="flex lg:hidden items-center justify-center">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="size-12 border-transparent bg-white"
|
||||
onClick={() => setIsSidebarOpen(true)}
|
||||
>
|
||||
<MenuIcon />
|
||||
</Button>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
export default Navbar;
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { ListFilterIcon, SearchIcon } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { BookmarkCheckIcon, ListFilterIcon, SearchIcon } from 'lucide-react';
|
||||
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useTRPC } from '@/trpc/client';
|
||||
|
||||
import CategoriesSidebar from './categories-sidebar';
|
||||
|
||||
@@ -15,6 +18,9 @@ interface SearchInputProps {
|
||||
const SearchInput = ({ disabled }: SearchInputProps) => {
|
||||
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
|
||||
|
||||
const trpc = useTRPC();
|
||||
const session = useQuery(trpc.auth.session.queryOptions());
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-center gap-2 w-full">
|
||||
@@ -40,6 +46,15 @@ const SearchInput = ({ disabled }: SearchInputProps) => {
|
||||
>
|
||||
<ListFilterIcon />
|
||||
</Button>
|
||||
|
||||
{session.data?.user && (
|
||||
<Button asChild variant="elevated">
|
||||
<Link href="/library">
|
||||
<BookmarkCheckIcon />
|
||||
Library
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export const AUTH_COOKIE = 'payload-token';
|
||||
@@ -1,21 +1,17 @@
|
||||
import { headers as getHeaders, cookies as getCookies } from "next/headers";
|
||||
import { headers as getHeaders } from "next/headers";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { AUTH_COOKIE } from "@/modules/auth/constants";
|
||||
import { loginSchema, registerSchema } from "@/modules/auth/schemas";
|
||||
import { baseProcedure, createTRPCRouter } from "@/trpc/init";
|
||||
|
||||
import { generateAuthCookie } from "../utils";
|
||||
|
||||
export const authRouter = createTRPCRouter({
|
||||
session: baseProcedure.query(async ({ ctx }) => {
|
||||
const headers = await getHeaders();
|
||||
|
||||
return await ctx.db.auth({ headers });
|
||||
}),
|
||||
logout: baseProcedure.mutation((async () => {
|
||||
const cookies = await getCookies();
|
||||
|
||||
cookies.delete(AUTH_COOKIE);
|
||||
})),
|
||||
register: baseProcedure
|
||||
.input(
|
||||
registerSchema
|
||||
@@ -62,13 +58,10 @@ export const authRouter = createTRPCRouter({
|
||||
})
|
||||
}
|
||||
|
||||
const cookies = await getCookies();
|
||||
cookies.set({
|
||||
name: AUTH_COOKIE,
|
||||
await generateAuthCookie({
|
||||
prefix: ctx.db.config.cookiePrefix,
|
||||
value: data.token,
|
||||
httpOnly: true,
|
||||
path: '/',
|
||||
});
|
||||
})
|
||||
}),
|
||||
login: baseProcedure
|
||||
.input(loginSchema)
|
||||
@@ -88,13 +81,10 @@ export const authRouter = createTRPCRouter({
|
||||
})
|
||||
}
|
||||
|
||||
const cookies = await getCookies();
|
||||
cookies.set({
|
||||
name: AUTH_COOKIE,
|
||||
await generateAuthCookie({
|
||||
prefix: ctx.db.config.cookiePrefix,
|
||||
value: data.token,
|
||||
httpOnly: true,
|
||||
path: '/',
|
||||
});
|
||||
})
|
||||
|
||||
return data;
|
||||
})
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
'use client';
|
||||
|
||||
import { toast } from "sonner";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { Poppins } from "next/font/google";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
|
||||
import { useTRPC } from "@/trpc/client";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { LoginSchema, loginSchema } from "@/modules/auth/schemas";
|
||||
import { useTRPC } from "@/trpc/client";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { Poppins } from "next/font/google";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { toast } from "sonner";
|
||||
|
||||
const poppins = Poppins({
|
||||
subsets: ['latin'],
|
||||
@@ -22,11 +23,13 @@ const poppins = Poppins({
|
||||
export const SignInView = () => {
|
||||
const router = useRouter();
|
||||
const trpc = useTRPC();
|
||||
const queryClient = useQueryClient();
|
||||
const login = useMutation(trpc.auth.login.mutationOptions({
|
||||
onError: (error) => {
|
||||
toast.error(error.message)
|
||||
},
|
||||
onSuccess: () => {
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(trpc.auth.session.queryFilter())
|
||||
router.push('/');
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { cookies as getCookies } from "next/headers";
|
||||
|
||||
interface Props {
|
||||
prefix: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const generateAuthCookie = async ({prefix, value}: Props) => {
|
||||
const cookies = await getCookies();
|
||||
|
||||
cookies.set({
|
||||
name: `${prefix}-token`,
|
||||
value,
|
||||
httpOnly: true,
|
||||
path: '/',
|
||||
})
|
||||
}
|
||||
@@ -21,6 +21,7 @@ export default buildConfig({
|
||||
baseDir: path.resolve(dirname),
|
||||
},
|
||||
},
|
||||
cookiePrefix: 'funroad',
|
||||
collections: [Users, Media, Categories],
|
||||
editor: lexicalEditor(),
|
||||
secret: process.env.PAYLOAD_SECRET || '',
|
||||
|
||||
+2
-1
@@ -11,4 +11,5 @@ export const trpc = createTRPCOptionsProxy({
|
||||
ctx: createTRPCContext,
|
||||
router: appRouter,
|
||||
queryClient: getQueryClient,
|
||||
});
|
||||
});
|
||||
export const caller = appRouter.createCaller(createTRPCContext);
|
||||
Reference in New Issue
Block a user