generated from iqbalpa/nextjs-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(auth): create signin page and its integration
- Loading branch information
Showing
14 changed files
with
348 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import axios from 'axios'; | ||
import { SignInRequest, SignUpRequest } from '@/constant/auth.constant'; | ||
|
||
const BASE_URL: string = 'http://localhost:3000'; | ||
|
||
export const signup = async (data: SignUpRequest) => { | ||
let res = await axios.post(`${BASE_URL}/auth/signup`, { | ||
name: data.name, | ||
email: data.email, | ||
password: data.password, | ||
}); | ||
res = res.data; | ||
return res; | ||
}; | ||
|
||
export const signin = async (data: SignInRequest) => { | ||
const res = await axios.post(`${BASE_URL}/auth/signin`, { | ||
email: data.email, | ||
password: data.password, | ||
}); | ||
const result = res.data; | ||
return result; | ||
}; |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import SignInModule from '@/modules/signin/signin'; | ||
|
||
export default function Page() { | ||
return <SignInModule />; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
export interface SignUpRequest { | ||
name: string; | ||
email: string; | ||
password: string; | ||
} | ||
|
||
export interface SignUpResponse { | ||
id: number; | ||
name: string; | ||
email: string; | ||
password: string; | ||
} | ||
|
||
export interface SignInRequest { | ||
email: string; | ||
password: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
'use client'; | ||
|
||
import Link from 'next/link'; | ||
import React, { useState } from 'react'; | ||
import { useForm, SubmitHandler } from 'react-hook-form'; | ||
import { toast } from 'react-toastify'; | ||
import 'react-toastify/dist/ReactToastify.css'; | ||
import { useDispatch } from 'react-redux'; | ||
import { setUser } from '@/store/userSlice'; | ||
import { decodeToken } from '@/utils/jwt-decode'; | ||
import { useRouter } from 'next/navigation'; | ||
import { setCookie } from 'cookies-next'; | ||
import { Eye, EyeOff, Mail } from 'lucide-react'; | ||
import { signin } from '@/api/auth.api'; | ||
|
||
type SignInInputs = { | ||
email: string; | ||
password: string; | ||
}; | ||
|
||
const SignInModule: React.FC = () => { | ||
const dispatch = useDispatch(); | ||
const router = useRouter(); | ||
const { | ||
register, | ||
handleSubmit, | ||
watch, | ||
formState: { errors }, | ||
} = useForm<SignInInputs>(); | ||
|
||
const [isPassVisible, setIsPassVisible] = useState<boolean>(false); | ||
const togglePassVisibility = () => { | ||
setIsPassVisible(!isPassVisible); | ||
}; | ||
|
||
const onSubmit: SubmitHandler<SignInInputs> = async (data) => { | ||
try { | ||
const res = await signin(data); | ||
if (!res) { | ||
toast.error('Login failed'); | ||
return; | ||
} | ||
setCookie('accessToken', res.access_token); // store access token in cookie. use getCookie('accessToken') | ||
|
||
console.log('decoding token...'); | ||
const user = decodeToken(res.access_token).user; | ||
console.log(user); | ||
dispatch(setUser(user)); | ||
toast.success('Login success'); | ||
setTimeout(() => { | ||
router.push('/'); | ||
}, 1500); | ||
} catch (error) { | ||
toast.error('An error occurred during logging in'); | ||
} | ||
}; | ||
|
||
return ( | ||
<div className="flex h-screen items-center justify-center bg-black bg-cover bg-no-repeat"> | ||
<div className="flex w-1/3 flex-col items-center justify-center border border-gray-200 bg-white bg-opacity-10 p-14 backdrop-blur-md backdrop-filter"> | ||
<h1 className="mb-5 text-xl font-bold uppercase text-white">Sign In</h1> | ||
<form | ||
onSubmit={handleSubmit(onSubmit)} | ||
className="flex w-full flex-col" | ||
> | ||
<div className="mb-2 flex flex-col"> | ||
<p className="mb-1 font-semibold text-white">Email</p> | ||
<div className="flex flex-row items-center"> | ||
<input | ||
placeholder="email" | ||
{...register('email', { required: true })} | ||
className="mr-2 grow rounded-md border-[1px] border-slate-400 px-4 py-2" | ||
/> | ||
<Mail color="#ffffff" size={35} /> | ||
</div> | ||
{errors.email && ( | ||
<span className="text-sm text-red-500"> | ||
This field is required | ||
</span> | ||
)} | ||
</div> | ||
<div className="mb-4 flex flex-col"> | ||
<p className="mb-1 font-semibold text-white">Password</p> | ||
<div className="flex flex-row items-center"> | ||
<input | ||
placeholder="password" | ||
type={isPassVisible ? 'text' : 'password'} | ||
{...register('password', { required: true })} | ||
className="mr-2 grow rounded-md border-[1px] border-slate-400 px-4 py-2" | ||
/> | ||
{isPassVisible ? ( | ||
<Eye | ||
color="#ffffff" | ||
size={35} | ||
onClick={togglePassVisibility} | ||
className="cursor-pointer" | ||
/> | ||
) : ( | ||
<EyeOff | ||
color="#ffffff" | ||
size={35} | ||
onClick={togglePassVisibility} | ||
className="cursor-pointer" | ||
/> | ||
)} | ||
</div> | ||
{errors.password && ( | ||
<span className="text-sm text-red-500"> | ||
This field is required | ||
</span> | ||
)} | ||
</div> | ||
<input | ||
type="submit" | ||
className="rounded-lg bg-emerald-500 px-4 py-2 text-white duration-100 hover:cursor-pointer hover:bg-emerald-700" | ||
/> | ||
</form> | ||
<p className="mt-5 text-sm text-white"> | ||
doesn't have an account?{' '} | ||
<Link href="/signup" className="text-green-500 hover:text-green-700"> | ||
register | ||
</Link> | ||
</p> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default SignInModule; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
'use client'; | ||
|
||
import { ReactNode } from 'react'; | ||
import { Provider } from 'react-redux'; | ||
import { store } from '@/store/userStore'; | ||
|
||
const UserProvider = ({ children }: { children: ReactNode }) => { | ||
return <Provider store={store}>{children}</Provider>; | ||
}; | ||
|
||
export default UserProvider; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'; | ||
|
||
interface User { | ||
id: number; | ||
name: string; | ||
email: string; | ||
password: string; | ||
} | ||
|
||
interface UserState { | ||
user: User | null; | ||
} | ||
|
||
const initialState: UserState = { | ||
user: null, | ||
}; | ||
|
||
const userSlice = createSlice({ | ||
name: 'user', | ||
initialState, | ||
reducers: { | ||
setUser: (state, action: PayloadAction<User>) => { | ||
state.user = action.payload; | ||
}, | ||
logout: (state) => { | ||
state.user = null; | ||
}, | ||
}, | ||
}); | ||
|
||
export const { setUser, logout } = userSlice.actions; | ||
|
||
export default userSlice.reducer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { configureStore } from '@reduxjs/toolkit'; | ||
import userReducer from './userSlice'; | ||
|
||
export const store = configureStore({ | ||
reducer: { | ||
user: userReducer, | ||
}, | ||
}); | ||
|
||
export type RootState = ReturnType<typeof store.getState>; | ||
export type AppDispatch = typeof store.dispatch; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { jwtDecode } from 'jwt-decode'; | ||
|
||
interface User { | ||
id: number; | ||
name: string; | ||
email: string; | ||
password: string; | ||
} | ||
|
||
interface DecodedToken { | ||
user: User; | ||
iat: number; | ||
exp: number; | ||
} | ||
|
||
export const decodeToken = (accessToken: string) => { | ||
const decoded = jwtDecode<DecodedToken>(accessToken); | ||
return decoded; | ||
}; |
Oops, something went wrong.