Skip to content

Commit

Permalink
full auth complited + logout
Browse files Browse the repository at this point in the history
  • Loading branch information
devyassin committed Aug 13, 2023
1 parent d381645 commit 596ff82
Show file tree
Hide file tree
Showing 11 changed files with 216 additions and 21 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ yarn-error.log*

# local env files
.env*.local

.env
# vercel
.vercel

Expand Down
18 changes: 18 additions & 0 deletions app/api/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import connect from "@/database/database";
import User from "@/models/User";
import { NextResponse, NextRequest } from "next/server";

connect();

export async function GET(
request: NextRequest,
{ params }: { params: { id: string } }
) {
const id = params.id;

const user = await User.findById(id);
if (!user) {
return NextResponse.json({ error: "User Not Found" });
}
return NextResponse.json({ user });
}
17 changes: 17 additions & 0 deletions app/api/logout/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { NextResponse } from "next/server";
import connect from "@/database/database";

connect();

export async function GET() {
try {
const response = NextResponse.json({
message: "Logout successfully",
success: true,
});
response.cookies.set("token", "", { httpOnly: true, expires: new Date(0) });
return response;
} catch (error: any) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
19 changes: 19 additions & 0 deletions app/api/me/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { NextRequest, NextResponse } from "next/server";
import connect from "@/database/database";
import User from "@/models/User";
import { getDataFromToken } from "@/helpers/GetDataFromToken";

connect();

export async function GET(request: NextRequest) {
try {
const userId = await getDataFromToken(request);
const user = await User.findOne({ _id: userId }).select("-password");
return NextResponse.json({
message: "User found",
data: user,
});
} catch (error: any) {
return NextResponse.json({ error: error.message }, { status: 400 });
}
}
22 changes: 21 additions & 1 deletion app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
"use client";
import FirstBtn from "@/components/btn/FirstBtn";
import Image from "next/image";
import { useDispatch } from "react-redux";
import { useAppSelector } from "@/store/store";
import { logOut } from "@/store/UserSlice";
import { useRouter } from "next/navigation";

export default function Home() {
return <div className="text-3xl font-bold">hello</div>;
const { push } = useRouter();
const dispatch = useDispatch<any>();
return (
<div
onClick={() => {
dispatch(logOut());
push("/signin");
}}
className="text-3xl font-bold"
>
<div>
<FirstBtn customClasses="mt-8 py-2 px-8" text="Logout" />
</div>
</div>
);
}
12 changes: 12 additions & 0 deletions helpers/GetDataFromToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { NextRequest } from "next/server";
import jwt from "jsonwebtoken";

export const getDataFromToken = (request: NextRequest) => {
try {
const token = request.cookies.get("token")?.value || "";
const decodedToken: any = jwt.verify(token, process.env.JWT_SECRET_KEY!);
return decodedToken.id;
} catch (error: any) {
throw new Error(error.message);
}
};
5 changes: 5 additions & 0 deletions lib/validation/UserValidation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@ export const UserValidation = z.object({
hourlyRate: z.number().min(0).optional(), // Assuming minimum hourly rate is 0
bio: z.string().min(3).max(1000).optional(),
});

export const UserValidationSignIn = z.object({
email: z.string().email(),
password: z.string().min(8),
});
29 changes: 23 additions & 6 deletions middleware.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { NextResponse, NextRequest } from "next/server";

// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
return NextResponse.redirect(new URL("/home", request.url));
const path = request.nextUrl.pathname;
const isPublicPath = path === "/signin" || path === "/signup" || path === "/welcome";

const token = request.cookies.get("token")?.value || "";

if (isPublicPath && token) {
return NextResponse.redirect(new URL("/", request.nextUrl));
}

if (!isPublicPath && !token) {
return NextResponse.redirect(new URL("/welcome", request.nextUrl));
}
}

// See "Matching Paths" below to learn more
export const config = {
matcher: "/about/:path*",
matcher: [
/*
* Match all request paths except for the ones starting with:
* - api (API routes)
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
*/
"/((?!api|_next/static|_next/image|favicon.ico).*)",
],
};
65 changes: 52 additions & 13 deletions pages/SignIn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ import InputPassword from "@/components/form/InputPassword";
import AskedSignIn from "@/components/ui/AskedSignIn";
import Copyright from "@/components/ui/Copyright";
import Image from "next/image";
import React, { FormEvent } from "react";
import React, { FormEvent, useEffect } from "react";
import { useAppSelector } from "@/store/store";
import { useDispatch } from "react-redux";
import { useRouter } from "next/navigation";
import { User } from "@/types";
import FirstBtn from "@/components/btn/FirstBtn";
import { zodHandllingErrors } from "@/helpers/ZodHandlingErrors";
import { UserValidationSignIn } from "@/lib/validation/UserValidation";
import { clearUser, signIn } from "@/store/UserSlice";
import { Toastfailed, ToastLoading, Toastsuccess } from "@/helpers/Toast";

type Props = {};

Expand All @@ -17,11 +21,33 @@ const SignIn = (props: Props) => {
const dispatch = useDispatch<any>();
const currentTypeSelected = useAppSelector((state) => state.welcome.type);
const user: User = useAppSelector((state) => state.user.user);
const error = useAppSelector((state) => state.user.error);
const statusAddUser = useAppSelector((state) => state.user.statusAddUser);
const errorSignIn = useAppSelector((state) => state.user.errorSignIn);
const statusSignIn = useAppSelector((state) => state.user.statusSignIn);
const onSubmitHandler = (e: FormEvent) => {
e.preventDefault();
if (zodHandllingErrors(UserValidationSignIn, user)) {
dispatch(signIn({ email: user.email, password: user.password }));
}
};

useEffect(() => {
if (statusSignIn === "succeeded") {
Toastsuccess("Welcome !");

setTimeout(() => {
router.push("/");
dispatch(clearUser());
}, 1500);
}

if (statusSignIn === "failed") {
Toastfailed(errorSignIn);
}

if (statusSignIn === "loading") {
ToastLoading("processing .....");
}
}, [statusSignIn]);
return (
<div className="flex flex-col px-6 pt-6 ">
<div
Expand All @@ -37,18 +63,31 @@ const SignIn = (props: Props) => {
/>
</div>
<div className="flex flex-col card-welcome mx-auto px-14 py-6 my-8 w-1/2 max-lg:w-2/3 max-sm:w-full ">
<h1 className="title-welcome max-lg:text-[24px] mb-[14px]">Sign In</h1>
<h1 className="title-welcome max-lg:text-[24px] mb-[14px]">
Sign In{" "}
{currentTypeSelected == "client" ? "as a client" : "As a Freelancer"}
</h1>
<div className="flex items-center justify-between ">
<hr className="h-[1px] mr-4 w-full bg-gray-50 opacity-30" />

<Image
src="/assets/clientLogo.png"
alt="client logo"
className="pt-2 max-md:pb-0 pb-8"
priority
width={50}
height={50}
/>
{currentTypeSelected == "client" ? (
<Image
src="/assets/clientLogo.png"
alt="client logo"
className="pt-2 max-md:pb-0 pb-8"
priority
width={50}
height={50}
/>
) : (
<Image
src="/assets/freelancerLogo.png"
alt="client logo"
className="pt-2 max-md:pb-0 pb-8"
priority
width={50}
height={50}
/>
)}

<hr className="h-[1px] ml-4 w-full bg-gray-50 opacity-30" />
</div>
Expand Down
1 change: 1 addition & 0 deletions pages/SignUp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const SignUp = (props: Props) => {

if (zodHandllingErrors(UserValidation, user)) {
dispatch(addUser(user));
router.push("/signin");
}
};

Expand Down
47 changes: 47 additions & 0 deletions store/UserSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,35 @@ export const addUser = createAsyncThunk(
}
);

// sign in
export const signIn = createAsyncThunk(
"users/signin",
async ({ email, password }: any, { rejectWithValue }) => {
try {
const response = await instance.post(`/signin`, { email, password });
return response.data;
} catch (error: any) {
return rejectWithValue(error);
}
}
);

// logout
export const logOut = createAsyncThunk("users/logout", async () => {
try {
const response = await instance.get("/logout");
return response.data;
} catch (error: any) {
return new Error(error.message);
}
});

// Define the initial user state
const initialUser = {
data: [],
statusAddUser: "",
statusSignIn: "",
statusLogout: "",
user: {
firstName: "",
lastName: "",
Expand All @@ -42,6 +67,8 @@ const initialUser = {
iscomplited: false,
},
error: "",
errorSignIn: "",
errorLogOut: "",
};

const userSlice = createSlice({
Expand Down Expand Up @@ -73,6 +100,26 @@ const userSlice = createSlice({
.addCase(addUser.rejected, (state, { payload }: any) => {
state.statusAddUser = "failed";
state.error = payload.response.data.message;
})
.addCase(signIn.pending, (state) => {
state.statusSignIn = "loading";
})
.addCase(signIn.fulfilled, (state, { payload }) => {
state.statusSignIn = "succeeded";
})
.addCase(signIn.rejected, (state, { payload }: any) => {
state.statusSignIn = "failed";
state.errorSignIn = payload.response.data.message;
})
.addCase(logOut.pending, (state) => {
state.statusLogout = "loading";
})
.addCase(logOut.fulfilled, (state, { payload }) => {
state.statusLogout = "succeeded";
})
.addCase(logOut.rejected, (state, { payload }: any) => {
state.statusLogout = "failed";
state.errorLogOut = payload.response.data.message;
});
},
});
Expand Down

0 comments on commit 596ff82

Please sign in to comment.