Skip to content

Commit

Permalink
feat(auth): login with credentials & getCurrentUser
Browse files Browse the repository at this point in the history
  • Loading branch information
tinspham209 committed May 5, 2023
1 parent 3a235c8 commit c447af6
Show file tree
Hide file tree
Showing 14 changed files with 313 additions and 27 deletions.
37 changes: 37 additions & 0 deletions app/actions/getCurrentUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { authOptions } from "@/pages/api/auth/[...nextauth]";
import { getServerSession } from "next-auth/next";
import prisma from "@/app/libs/prismadb";

export async function getSession() {
return await getServerSession(authOptions);
}

export default async function getCurrentUser() {
try {
const session = await getSession();

if (!session?.user?.email) {
return null;
}

const currentUser = await prisma.user.findUnique({
where: {
email: session.user.email as string,
},
});

if (!currentUser) {
return null;
}

return {
...currentUser,
createdAt: currentUser.createdAt.toISOString(),
updatedAt: currentUser.updatedAt.toISOString(),
emailVerified: currentUser.emailVerified?.toISOString() || null,
};
} catch (error) {
console.log("error: ", error);
return null;
}
}
1 change: 1 addition & 0 deletions app/actions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as getCurrentUser } from "./getCurrentUser";
9 changes: 7 additions & 2 deletions app/components/modals/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ interface Props {
disabled?: boolean;
secondaryAction?: () => void;
secondaryActionLabel?: string;
isLoading?: boolean;
}
const Modal: React.FC<Props> = ({
actionLabel,
onClose = () => {},
onSubmit = () => {},
body,
footer,

isLoading,
disabled,
isOpen,
secondaryAction,
Expand Down Expand Up @@ -102,7 +103,11 @@ const Modal: React.FC<Props> = ({
{secondaryActionLabel}
</Button>
)}
<Button onClick={handleSubmit} disabled={disabled}>
<Button
onClick={handleSubmit}
disabled={disabled}
loading={isLoading}
>
{actionLabel}
</Button>
</div>
Expand Down
117 changes: 117 additions & 0 deletions app/components/modals/loginModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
"use client";

import axios from "axios";
import React from "react";
import { FieldValues, SubmitHandler, useForm } from "react-hook-form";
import { FcGoogle } from "react-icons/fc";
import { AiFillGithub } from "react-icons/ai";
import { ROUTE } from "@/app/api/constant";
import { useRegisterModal, useLoginModal } from "@/app/hooks";
import { toast } from "react-hot-toast";
import Modal from ".";
import Heading from "../heading";
import Input from "../inputs";
import InputPassword from "../inputs/password";
import Button from "../button";
import { signIn } from "next-auth/react";
import { useRouter } from "next/navigation";
const LoginModal = () => {
const router = useRouter();
const registerModal = useRegisterModal();
const loginModal = useLoginModal();
const [isLoading, setIsLoading] = React.useState(false);

const {
register,
handleSubmit,
setError,
formState: { errors },
} = useForm<FieldValues>({
defaultValues: {
email: "",
password: "",
},
});

const onSubmit: SubmitHandler<FieldValues> = (data) => {
setIsLoading(true);

signIn("credentials", {
...data,
redirect: false,
}).then((callback) => {
setIsLoading(false);

if (callback?.ok) {
toast.success("Logged in successfully!");
router.refresh();
loginModal.onClose();
}
if (callback?.error) {
setError("password", {
message: callback.error,
});
}
});
};

return (
<Modal
disabled={isLoading}
isLoading={isLoading}
isOpen={loginModal.isOpen}
title="Login"
actionLabel="Continue"
onClose={loginModal.onClose}
onSubmit={handleSubmit(onSubmit)}
body={
<div className="flex flex-col gap-4">
<Heading title="Welcome back" subTitle="Login to your account!" />
<Input
id="email"
label="Email"
disabled={isLoading}
register={register}
errors={errors}
required
type="email"
/>
<InputPassword
id="password"
label="Password"
disabled={isLoading}
register={register}
errors={errors}
required
/>
</div>
}
footer={
<div className="flex flex-col gap-4 mt-3">
<hr />
<Button outline onClick={() => {}} icon={FcGoogle}>
Continue with Google
</Button>
<Button outline onClick={() => {}} icon={AiFillGithub}>
Continue with Github
</Button>
<div className="text-neutral-500 text-center mt-4 font-light">
<div className="justify-center flex flex-row items-center gap-2">
<div>Already have an account?</div>
<div
className="text-neutral-800 cursor-pointer hover:underline"
onClick={() => {
registerModal.onClose();
}}
>
Login
</div>
</div>
</div>
</div>
}
/>
);
};

export default LoginModal;
4 changes: 3 additions & 1 deletion app/components/modals/registerModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ import { FieldValues, SubmitHandler, useForm } from "react-hook-form";
import { FcGoogle } from "react-icons/fc";
import { AiFillGithub } from "react-icons/ai";
import { ROUTE } from "@/app/api/constant";
import useRegisterModal from "@/app/hooks/useRegisterModal";
import { useRegisterModal } from "@/app/hooks";
import { toast } from "react-hot-toast";
import Modal from ".";
import Heading from "../heading";
import Input from "../inputs";
import InputPassword from "../inputs/password";
import Button from "../button";

const RegisterModal = () => {
const registerModal = useRegisterModal();
const [isLoading, setIsLoading] = React.useState(false);
Expand Down Expand Up @@ -48,6 +49,7 @@ const RegisterModal = () => {
return (
<Modal
disabled={isLoading}
isLoading={isLoading}
isOpen={registerModal.isOpen}
title="Register"
actionLabel="Continue"
Expand Down
2 changes: 2 additions & 0 deletions app/components/modals/wrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
"use client";
import React from "react";
import RegisterModal from "./registerModal";
import LoginModal from "./loginModal";

const ModalWrapper = () => {
return (
<>
<RegisterModal />
<LoginModal />
</>
);
};
Expand Down
9 changes: 7 additions & 2 deletions app/components/navbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,21 @@ import Container from "../container";
import Logo from "./logo";
import Search from "./search";
import UserMenu from "./userMenu";
import { User } from "@prisma/client";

const Navbar = () => {
interface Props {
currentUser?: User | null;
}

const Navbar: React.FC<Props> = ({ currentUser }) => {
return (
<div className="fixed w-full bg-white z-10 shadow-sm">
<div className="py-4 border-b-[1px]">
<Container>
<div className="flex flex-row items-center justify-between gap-3 md:gap-0">
<Logo />
<Search />
<UserMenu />
<UserMenu currentUser={currentUser} />
</div>
</Container>
</div>
Expand Down
13 changes: 9 additions & 4 deletions app/components/navbar/menuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@
import React from "react";

interface Props {
onClick: () => void;
onClick?: () => void;
label: string;
disabled?: boolean;
}

const MenuItem: React.FC<Props> = ({ label, onClick }) => {
const MenuItem: React.FC<Props> = ({ label, onClick, disabled }) => {
return (
<div
onClick={onClick}
className="px-4 py-3 hover:bg-neutral-50 transition font-semibold"
onClick={() => {
if (onClick) onClick();
}}
className={`px-4 py-3 hover:bg-neutral-50 transition font-semibold ${
disabled ? "hover:bg-white cursor-default" : ""
}`}
>
{label}
</div>
Expand Down
Loading

0 comments on commit c447af6

Please sign in to comment.