-
Notifications
You must be signed in to change notification settings - Fork 0
Implement login and signup UI with form validation and toggle functio… #1
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,5 +1,134 @@ | ||||||
| import { useState } from 'react'; | ||||||
| import { heroSectionData } from '../assets/assets'; | ||||||
| import { Link, useNavigate } from 'react-router-dom'; | ||||||
| import { BikeIcon, EyeIcon, EyeOffIcon, LockIcon, MailIcon, UserIcon } from 'lucide-react'; | ||||||
| import { LoaderIcon } from 'react-hot-toast'; | ||||||
|
|
||||||
| const Login = () => { | ||||||
| return <div>Login</div>; | ||||||
| const [isLogin, setIsLogin] = useState(true); | ||||||
| const [name, setName] = useState(''); | ||||||
| const [email, setEmail] = useState(''); | ||||||
| const [showPassword, setShowPassword] = useState(false); | ||||||
|
|
||||||
| const [password, setPassword] = useState(''); | ||||||
| const [loading, setLoading] = useState(false); | ||||||
| const navigate = useNavigate(); | ||||||
| const handleSubmit = async (e: React.SubmitEvent) => { | ||||||
| e.preventDefault(); | ||||||
| setLoading(true); | ||||||
| setTimeout(() => { | ||||||
| navigate('/'); | ||||||
| }, 1000); | ||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||
| }; | ||||||
|
Comment on lines
+16
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Authentication logic is missing. The submit handler only sets a loading state and redirects—there's no actual authentication call to a backend API. This means anyone can access the app without valid credentials. Based on the context snippets, This is a critical security gap for production. You'll need to:
Do you want me to open an issue with a template for implementing proper authentication with JWT tokens and protected routes? 🤖 Prompt for AI Agents
Comment on lines
+18
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add cleanup for setTimeout and reset loading state properly. The 🛡️ Proposed fix with cleanup const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setLoading(true);
- setTimeout(() => {
- window.location.href = '/';
- }, 1000);
+ const timeoutId = setTimeout(() => {
+ navigate('/');
+ setLoading(false);
+ }, 1000);
+
+ // Cleanup function
+ return () => clearTimeout(timeoutId);
};Even better, use 🤖 Prompt for AI Agents |
||||||
| return ( | ||||||
| <div className='min-h-screen flex'> | ||||||
| {/* left-side */} | ||||||
| <div className=' hidden lg:flex lg:w-1/2 bg-app-green relative items-center justify-center'> | ||||||
| <img | ||||||
| src={heroSectionData.hero_image} | ||||||
| alt='background image for login' | ||||||
| aria-label=' background image for login' | ||||||
| className=' absolute inset-0 object-cover h-full bg-center opacity-10 ' | ||||||
| /> | ||||||
| <div className=' relative text-center px-12'> | ||||||
| <h2 className=' text-4xl text-semibold text-white mb-4'>Welcome back to Instacart</h2> | ||||||
| <p className='text-white/60 font-serif text-xl max-w-sm mx-auto'>Fresh groceries and organic produce, delivered to your doorstep.</p> | ||||||
| </div> | ||||||
| </div> | ||||||
| {/* right-side */} | ||||||
| <div className='flex-1 flex-center px-4 py-2 bg-app-cream'> | ||||||
| <div className='w-full max-w-md'> | ||||||
| {/* header form */} | ||||||
| <div className='text-center mb-8'> | ||||||
| <Link to='/' className='inline-flex items-center gap-2 mb-6'> | ||||||
| <BikeIcon className='size-8 text-app-green' /> <span className='text-3xl font-semibold text-app-green'>Instacart</span> | ||||||
| </Link> | ||||||
| <h1 className='text-2xl font-semibold text-app-green mb-2'>{isLogin ? 'Sign in to your account' : 'Sign up For a new account'}</h1> | ||||||
| <p className=' text-sm text-app-text-light"'> | ||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||
| {isLogin ? "Don't have an account?" : 'Already have an account?'}{' '} | ||||||
| <button type='button' className=' text-orange-500 ml-1 font-semibold hover:text-orange-600 transition-colors" >' onClick={() => setIsLogin(!isLogin)}> | ||||||
| {isLogin ? 'Create an account' : 'Sign In'} | ||||||
| </button> | ||||||
| </p> | ||||||
| </div> | ||||||
| {/* form for sing in ans signup */} | ||||||
| <form onSubmit={handleSubmit} className='space-y-6'> | ||||||
| {!isLogin && ( | ||||||
| <div> | ||||||
| <label htmlFor='name' className='text-sm flex flex-col gap-1'> | ||||||
| {' '} | ||||||
| Name | ||||||
| <div className='relative'> | ||||||
| <UserIcon className='absolute left-3.5 top-1/2 -translate-y-1/2 size-4 text-app-text-light' /> | ||||||
| <input | ||||||
| type='text' | ||||||
| id='name' | ||||||
| value={name} | ||||||
| onChange={(e) => setName(e.target.value)} | ||||||
| required | ||||||
| placeholder='Enter your name' | ||||||
| className='w-full rounded-xl pl-10 pr-4 py-3 text-sm bg-white border not-focus:border-app-border transition-all' | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: In Tailwind CSS v4, the Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE="client/src/pages/Login.tsx"
# Show the relevant section around the Name input and the className line.
nl -ba "$FILE" | sed -n '40,110p'Repository: React-projects/Instacart---Grocery-Delivery Length of output: 130 🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE="client/src/pages/Login.tsx"
# Show relevant section around the Name input and className line
cat -n "$FILE" | sed -n '45,95p'Repository: React-projects/Instacart---Grocery-Delivery Length of output: 3774 🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE="client/src/pages/Login.tsx"
echo "== Tailwind focus/border usage in this file =="
rg -n "focus:|not-focus:|border-app-border|border-" "$FILE" || true
echo
echo "== Name/email/password validation attributes =="
rg -n "minLength|maxLength|pattern|aria-|required|type='text'|type='email'|type='password'" "$FILE" || true
echo
echo "== handleSubmit and any client-side validation around name/email/password =="
rg -n "handleSubmit|setName|setEmail|setPassword|name\\b|email\\b|password\\b" "$FILE" || trueRepository: React-projects/Instacart---Grocery-Delivery Length of output: 2559 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Locate where tailwind config lives (common names)
ls -1 | rg -i "tailwind\\.config\\.(js|ts|cjs|mjs|mjs)$" || true
ls -1 | rg -i "postcss\\.config\\.(js|cjs|mjs)$" || true
fd -t f -i "tailwind.config.*" . || true
echo "---- Search for app-border definition ----"
rg -n "app-border" . || true
echo "---- Search for focus border utilities elsewhere in Login page (and nearby components) ----"
rg -n "focus:.*border|focus:.*ring|ring:.*focus" client/src/pages/Login.tsx || true
echo "---- Search for any global/input focus border styles ----"
rg -n "focus.*border|not-focus:.*border|input.*focus|ring.*focus" client/src -S || trueRepository: React-projects/Instacart---Grocery-Delivery Length of output: 2678 🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE="client/src/index.css"
echo "== client/src/index.css (focus rules) =="
cat -n "$FILE" | sed -n '40,90p'Repository: React-projects/Instacart---Grocery-Delivery Length of output: 1349 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== Tailwind config files =="
fd -t f -i "tailwind.config.*" . || true
echo
echo "== package.json / Tailwind version =="
fd -t f -i "package.json" client . || true
# If there are multiple, print the ones that mention tailwind
rg -n "\"tailwindcss\"|tailwindcss" -S client package.json . 2>/dev/null || true
echo
echo "== Search for color/app-border mapping in config =="
fd -t f -i "tailwind.config.*" client . | xargs -r rg -n "app-border|border-app-border|--color-app-border|colors" || true
echo
echo "== Any CSS using border-app-border token (to infer mapping) =="
rg -n "border-app-border" client/src index.css client/index.css 2>/dev/null || trueRepository: React-projects/Instacart---Grocery-Delivery Length of output: 8544 🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE="client/src/index.css"
cat -n "$FILE" | sed -n '1,60p'Repository: React-projects/Instacart---Grocery-Delivery Length of output: 1865 Switch from
Suggested change- className='w-full rounded-xl pl-10 pr-4 py-3 text-sm bg-white border not-focus:border-app-border transition-all'
+ className='w-full rounded-xl pl-10 pr-4 py-3 text-sm bg-white border border-app-border focus:border-app-green focus:ring-2 focus:ring-app-green/20 transition-all'📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| arial-label='name input field' | ||||||
| /> | ||||||
| </div> | ||||||
| </label> | ||||||
| </div> | ||||||
| )} | ||||||
| <label htmlFor='email' className='text-sm flex flex-col gap-1'> | ||||||
| {' '} | ||||||
| Email Address | ||||||
| <div className='relative'> | ||||||
| <MailIcon className='absolute left-3.5 top-1/2 -translate-y-1/2 size-4 text-app-text-light' /> | ||||||
| <input | ||||||
| type='email' | ||||||
| id='email' | ||||||
| value={email} | ||||||
| onChange={(e) => setEmail(e.target.value)} | ||||||
| required | ||||||
| placeholder='Enter your email' | ||||||
| className='w-full rounded-xl pl-10 pr-4 py-3 text-sm bg-white border not-focus:border-app-border transition-all' | ||||||
| arial-label='email input field' | ||||||
| /> | ||||||
| </div> | ||||||
| </label> | ||||||
| <label htmlFor='password' className='text-sm flex flex-col gap-1'> | ||||||
| {' '} | ||||||
| Password | ||||||
| <div className='relative'> | ||||||
| <LockIcon className='absolute left-3.5 top-1/2 -translate-y-1/2 size-4 text-app-text-light' /> | ||||||
| <input | ||||||
| type={showPassword ? 'text' : 'password'} | ||||||
| id='password' | ||||||
| value={password} | ||||||
| onChange={(e) => setPassword(e.target.value)} | ||||||
| required | ||||||
| placeholder='Enter your password' | ||||||
| className='w-full rounded-xl pl-10 pr-4 py-3 text-sm bg-white border not-focus:border-app-border transition-all' | ||||||
| arial-label='password input field' | ||||||
| /> | ||||||
| <button | ||||||
| type='button' | ||||||
| className='absolute right-3 top-1/2 -translate-y-1/2 text-slate-400 hover:text-slate-600 transition-colors' | ||||||
| onClick={() => { | ||||||
| setShowPassword(!showPassword); | ||||||
| }} | ||||||
| > | ||||||
| {showPassword ? <EyeOffIcon size={18} /> : <EyeIcon size={18} />} | ||||||
| </button> | ||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||
| </div> | ||||||
| </label> | ||||||
| <button | ||||||
| type='submit' | ||||||
| disabled={loading} | ||||||
| className=' flex flex-center w-full py-3 bg-green-950 text-white font-semibold rounded-xl hover:bg-green-900 transition-colors disabled:opacity-50' | ||||||
| > | ||||||
| {loading ? <LoaderIcon className='size-8 animate-spin' /> : isLogin ? 'Sign In' : 'Sign Up'} | ||||||
| </button> | ||||||
| </form> | ||||||
| </div> | ||||||
| </div> | ||||||
| </div> | ||||||
| ); | ||||||
| }; | ||||||
|
|
||||||
| export default Login; | ||||||
Uh oh!
There was an error while loading. Please reload this page.