Skip to content

Login, register and logout logic completed #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 82 additions & 29 deletions app/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,59 +1,112 @@
'use client'

import { useRouter } from 'next/navigation';
import { login } from "@/utils/actions";
import Image from "next/image"
import Link from "next/link";
import { useState } from "react";
import { useEffect, useState } from "react";
import { useActionState } from "react";
import { FaEye } from "react-icons/fa";
import { IoCheckbox } from "react-icons/io5";
import { MdCheckBoxOutlineBlank } from "react-icons/md";
import { startTransition } from "react";
import { useGlobalContext } from '@/context/context';

const initialState: {
message:string | null, errors?: Record<string, string[] | undefined>,
isLoggedIn?:boolean,
accessToken?: string | null,
userId?: string | null
} = {
message:null,
isLoggedIn:false,
errors:{},
accessToken: null,
userId: null
}

const Login = () => {
const [isChecked, setIsChecked] = useState<boolean>(false);
const [togglePassword, setTogglePassword] = useState<boolean>(false);
const [state, formAction] = useActionState(login, initialState);
const [loading, setLoading] = useState<boolean>(false);
const {setUserId} = useGlobalContext();
const router = useRouter();

const handleCheckboxToggle = () => {
setIsChecked((prev) => !prev);
};

const handleSubmit = async (e:React.FormEvent<HTMLElement>) => {
e.preventDefault();
setLoading(true);
const formData = new FormData(e.currentTarget as HTMLFormElement)
startTransition(() => {
formAction(formData);
setLoading(false);
});

}

useEffect(()=>{
if(state?.isLoggedIn){
const userId = state?.userId as string
setUserId(userId)
router.push("/")
}
},[state])

const handleCheckboxToggle = () => {
setIsChecked((prev) => !prev);
};

return (
return (
<div className="grid grid-cols-5 gap-8 mx-5 md:gap-12 max-w-screen" style={{ height: 'calc(100vh - 4rem)' }}>
<form action="" method='POST' className="col-span-5 max-w-lg sm:max-w-4xl mt-8 sm:mt-16 sm:col-span-3 md:col-span-2">
<form onSubmit={handleSubmit} method='POST' className="col-span-5 max-w-lg sm:max-w-4xl mt-8 sm:mt-16 sm:col-span-3 md:col-span-2">
<h1 className="heading text-2xl font-bold">Welcome!</h1>
<p className="para mb-5 mt-2">Log In your account.</p>
{(state?.errors?.root) && <>
<div className="flex gap-2">
<p className="error-message font-bold mb-4 text-sm">
{state?.errors?.root}
</p>
</div>
</>}
<div className="flex flex-col mb-5">
<label className="label" htmlFor="email">Email <span className="asterik">*</span></label>
<input type="email" className="input value w-full mt-2" id="email" placeholder="Your Email" required/>
<input type="email" name="email" className="input value w-full mt-2" id="email" placeholder="Your Email" required/>
{state.errors && state.errors.email && (
<p className="error-message">{state.errors.email}</p>
)}
</div>
<div className="flex flex-col mb-5 relative">
<label className="label" htmlFor="password">Password <span className="asterik">*</span></label>
<div className="flex mt-2 relative">
<input type={togglePassword ?"text" :"password"} className="input value w-full pr-12" id="password" placeholder="Password" required/>
<input type={togglePassword ?"text" :"password"} name="password" className="input value w-full pr-12" id="password" placeholder="Password" required/>
<div className="flex justify-center items-center py-1 px-4 rounded-lg box-border cursor-pointer absolute top-0 right-0 bottom-0" onClick={()=>setTogglePassword(!togglePassword)}>
<FaEye className="value"/>
</div>
</div>
{state.errors && state.errors.password && (
<p className="error-message">{state.errors.password}</p>
)}
</div>
<div className="flex justify-between items-center">
<label className="label flex justify-between items-center gap-2 w-full">
<div className="label flex items-center gap-2">
{isChecked ? (
<IoCheckbox
className="primary border-0 text-xl"
onClick={handleCheckboxToggle}
/>
) : (
<MdCheckBoxOutlineBlank
className="primary border-0 text-xl"
onClick={handleCheckboxToggle}
/>
)}
<input type="checkbox" hidden />
Remember me
</div>
<Link href={""} className="label hover:underline">Forget Password?</Link>
</label>
<label className="label flex justify-between items-center gap-2 w-full">
<div className="label flex items-center gap-2">
{isChecked ? (
<IoCheckbox
className="primary border-0 text-xl"
onClick={handleCheckboxToggle}
/>
) : (
<MdCheckBoxOutlineBlank
className="primary border-0 text-xl"
onClick={handleCheckboxToggle}
/>
)}
<input type="checkbox" hidden data-testid="checkbox"/>
Remember me
</div>
<Link href={""} className="label hover:underline">Forget Password?</Link>
</label>
</div>
<button className="primaryBtn w-full mt-6">Login</button>
<button className="primaryBtn w-full mt-6" disabled={loading} data-testid="submit">{loading ? "Processing...": "Login"}</button>
<p className="para text-sm mt-4 text-center">Don&#39;t have any account? <Link href={'/register'} className="heading font-bold">SignUp</Link></p>
</form>
<div className="relative hidden sm:block col-span-1 sm:col-span-2 md:col-span-3 h-full">
Expand Down
81 changes: 65 additions & 16 deletions app/(auth)/register/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,57 +3,105 @@
import Image from "next/image"
import Link from "next/link";
import { useState } from "react";
import { useFormState } from "react-dom";
import { FaEye } from "react-icons/fa";
import { IoCheckbox } from "react-icons/io5";
import { MdCheckBoxOutlineBlank } from "react-icons/md";
import { startTransition } from "react";



// actions
import { createUser } from "@/utils/actions";

const initialState: { message: string | null; errors?: Record<string, string[] | undefined> } = {
message: null,
errors: {},
};

const Register = () => {
const [isChecked, setIsChecked] = useState<boolean>(false);
const [togglePassword, setTogglePassword] = useState<boolean>(false);
const [toggleConfirmPassword, setToggleConfirmPasword] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(false);
const [state,formAction] = useFormState(createUser,initialState)

const handleSubmit = async (e:React.FormEvent<HTMLElement>) => {
e.preventDefault();
setLoading(true);
const formData = new FormData(e.currentTarget as HTMLFormElement)
startTransition(() => {
formAction(formData);
setLoading(false);
});

const handleCheckboxToggle = () => {
setIsChecked((prev) => !prev);
};
}

return (
<div className="grid grid-cols-5 gap-8 mx-5 md:gap-12 max-w-screen" style={{ height: 'calc(100vh - 4rem)' }}>
<form action="" method='POST' className="col-span-5 max-w-lg sm:max-w-4xl mt-8 sm:mt-16 sm:col-span-3 md:col-span-2">
<form onSubmit={handleSubmit} action={formAction} method='POST' className="col-span-5 max-w-lg sm:max-w-4xl mt-8 sm:mt-16 sm:col-span-3 md:col-span-2">
<h1 className="heading text-2xl font-bold">Register!</h1>
<p className="para mb-5 mt-2">Create a new account.</p>

{(state?.message) && <>
<div className="flex gap-2">
<p className="success-message text-green-500 mb-4 font-bold">
{state?.message}
</p>
<Link href={"/login"} className="heading underline cursor-pointer font-bold text-xs">Login here</Link>
</div>
</>}
{(state?.errors?.root) && <>
<div className="flex gap-2">
<p className="error-message font-bold mb-4 text-sm">
{state?.errors?.root}
</p>
</div>
</>}
<div className="flex flex-col mb-5">
<label className="label" htmlFor="firstName">First Name <span className="asterik">*</span></label>
<input type="text" className="input value w-full mt-2" id="firstName" placeholder="First Name" required/>
<input type="text" name="firstName" className="input value w-full mt-2" id="firstName" placeholder="First Name" required/>
{state.errors && state.errors.firstName && (
<p className="error-message">{state.errors.firstName}</p>
)}
</div>
<div className="flex flex-col mb-5">
<label className="label" htmlFor="lastName">Last Name <span className="asterik">*</span></label>
<input type="text" className="input value w-full mt-2" id="lastName" placeholder="Last Name" required/>
<input type="text" name="lastName" className="input value w-full mt-2" id="lastName" placeholder="Last Name" required/>
{state.errors && state.errors.lastName && (
<p className="error-message">{state.errors.lastName}</p>
)}
</div>
<div className="flex flex-col mb-5">
<label className="label" htmlFor="email">Email <span className="asterik">*</span></label>
<input type="email" className="input value w-full mt-2" id="email" placeholder="Your Email" required/>
<input type="email" name="email" className="input value w-full mt-2" id="email" placeholder="Your Email" required/>
{state.errors && state.errors.email && (
<p className="error-message">{state.errors.email}</p>
)}
</div>
<div className="flex flex-col mb-5 relative">
<div className="flex flex-col mb-5 relative z-0">
<label className="label" htmlFor="password">Password <span className="asterik">*</span></label>
<div className="flex mt-2 relative">
<input type={togglePassword ?"text" :"password"} className="input value w-full pr-12" id="password" placeholder="Password" required/>
<input type={togglePassword ?"text" :"password"} name="password" className="input value w-full pr-12" id="password" placeholder="Password" required/>
<div className="flex justify-center items-center py-1 px-4 rounded-lg box-border cursor-pointer absolute top-0 right-0 bottom-0" onClick={()=>setTogglePassword(!togglePassword)}>
<FaEye className="value"/>
</div>
</div>
{state.errors && state.errors.password && (
<p className="error-message">{state.errors.password}</p>
)}

</div>
<div className="flex flex-col mb-5 relative w-full">
<label className="label" htmlFor="confirmPassword">Confirm Password <span className="asterik">*</span></label>
<div className="flex mt-2 relative">
<input type={toggleConfirmPassword ?"text" :"password"} className="input value w-full pr-12" id="confirmPassword" placeholder="Confirm Password" required/>
<input type={toggleConfirmPassword ?"text" :"password"} name="confirmPassword" className="input value w-full pr-12" id="confirmPassword" placeholder="Confirm Password" required />
<div className="flex justify-center items-center py-1 px-4 rounded-lg box-border cursor-pointer absolute top-0 right-0 bottom-0" onClick={()=>setToggleConfirmPasword(!toggleConfirmPassword)}>
<FaEye className="value"/>
</div>
</div>
{state.errors && state.errors.confirmPassword && (
<p className="error-message">{state.errors.confirmPassword}</p>
)}
</div>
<div>
{/* <div>
<label className="label flex items-center gap-2">
{isChecked ? (
<IoCheckbox
Expand All @@ -69,8 +117,9 @@ const Register = () => {
<input type="checkbox" hidden />
Remember me
</label>
</div>
<button className="primaryBtn w-full mt-6">Register</button>
</div> */}
<button className="primaryBtn w-full mt-6" disabled={loading}>{loading ? "Processing...": "Register"}</button>

<p className="para text-sm mt-4 text-center">Do you have an account? <Link href={'/login'} className="heading font-bold">SignIn</Link></p>
</form>
<div className="relative hidden sm:block col-span-1 sm:col-span-2 md:col-span-3 h-full">
Expand Down
80 changes: 80 additions & 0 deletions app/(profile)/create-post/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React from 'react'
import { FaImage } from "react-icons/fa";

const CreateBlog = () => {
return (
<div className='background p-6 rounded-lg max-w-4xl'>
<h1 className='text-xl font-bold mb-8'>Create a new blog</h1>
<form>
<p className='label mb-3'>Upload blog cover&nbsp;<span className='asterik'>*</span></p>
<label htmlFor="blogCover" className='border-2 border-dashed rounded-lg h-40 flex flex-col gap-2 justify-center items-center cursor-pointer mb-5 secondaryBg'>
<FaImage className='label text-3xl'/>
<p className='text-xs'>Upload Blog Cover Image</p>
<p className='text-xs'>click to browse</p>
<input type='file' name='blogCover' id='blogCover' className='hidden'/>
</label>
<div className="flex flex-col mb-5">
<label className="label" htmlFor="blogName">Blog Name <span className="asterik">*</span></label>
<input
type="text"
name="blogName"
className="input value w-full mt-2"
id="blogName"
required
placeholder='Eg. Next.js 15 is know released.'
/>
{/* {state.errors && state.errors.email && (
<p className="error-message">{state.errors.email}</p>
)} */}
</div>
<div className="flex flex-col mb-5">
<label className="label" htmlFor="hook">Hook <span className="asterik">*</span></label>
<input
type="text"
name="hook"
className="input value w-full mt-2"
id="hook"
placeholder='Eg. Did you know why next.js is so important? I tell you why'
required
/>
{/* {state.errors && state.errors.email && (
<p className="error-message">{state.errors.email}</p>
)} */}
</div>
<div className="flex flex-col mb-5">
<label className="label" htmlFor="desc">
Description <span className="asterik">*</span>
</label>
<textarea
name="desc"
id="desc"
className="input value w-full mt-2"
rows={10}
required
placeholder='Eg. <h1>What is Next.js.</h1>'
/>
{/* {state.errors?.desc && (
<p className="error-message">{state.errors.desc}</p>
)} */}
</div>
<p className='label mb-3'>Tags&nbsp;<span className='asterik'>*</span></p>
<div className='myBorder rounded-lg h-24 p-3 gap-2 items-center cursor-pointer mb-5 flex flex-wrap justify-start'>
<span className='tag cursor-pointer hover:tagSelected'>Design</span>
<span className='tag cursor-pointer hover:tagSelected'>Research</span>
<span className='tag cursor-pointer hover:tagSelected'>Technology</span>
<span className='tag cursor-pointer hover:tagSelected'>Polotics</span>
</div>
<div className='flex justify-between mt-10'>
<button className='transparentBtn'>Cancel</button>
<div className='flex gap-7'>
<button className='secondaryBtn'>Save as Draft</button>
<button className='primaryBtn'>Publish</button>
</div>
</div>

</form>
</div>
)
}

export default CreateBlog
Loading
Loading