Skip to content

Commit 797bbe8

Browse files
committed
React Password Generator [ReactJS Challenge AbdulBasit313#2]
Implemented the following: - Initial password display and regeneration - Copy password to clipboard - Checkbox functionality - Automatic checkbox selection - Password length validation - Password strength logic - Visual password strength representation
1 parent 118297d commit 797bbe8

1 file changed

Lines changed: 103 additions & 12 deletions

File tree

  • password-generator/src/components/PasswordGenerator

password-generator/src/components/PasswordGenerator/index.tsx

Lines changed: 103 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,80 @@ import refreshIcon from '../../assets/icons/refresh.svg'
1212
import './index.css'
1313

1414
const PasswordGenerator = () => {
15-
const [passwordLength, setPasswordLength] = useState<number>(10)
15+
const [passwordLength, setPasswordLength] = useState<number>(8)
16+
const [password, setPassword] = useState<string>('')
17+
const [copied, setCopied] = useState<boolean>(false)
18+
const [includeUppercase, setIncludeUppercase] = useState<boolean>(true)
19+
const [includeLowercase, setIncludeLowercase] = useState<boolean>(true)
20+
const [includeNumbers, setIncludeNumbers] = useState<boolean>(true)
21+
const [includeSpecialChars, setIncludeSpecialChars] = useState<boolean>(true)
22+
23+
const generatePassword = () => {
24+
const uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
25+
const lowercase = 'abcdefghijklmnopqrstuvwxyz'
26+
const numbers = '0123456789'
27+
const specialChars = '!@#$%^&*()_+-=[]{}|;:,.<>?'
28+
29+
let allChars = ''
30+
if (includeUppercase) allChars += uppercase
31+
if (includeLowercase) allChars += lowercase
32+
if (includeNumbers) allChars += numbers
33+
if (includeSpecialChars) allChars += specialChars
34+
35+
if (allChars === '') {
36+
setPassword('')
37+
return
38+
}
39+
40+
let generatedPassword = ''
41+
for (let i = 0; i < passwordLength; i++) {
42+
const randomIndex = Math.floor(Math.random() * allChars.length)
43+
generatedPassword += allChars[randomIndex]
44+
}
45+
46+
setPassword(generatedPassword)
47+
}
48+
49+
useEffect(() => {
50+
if (!includeUppercase && !includeLowercase && !includeNumbers && !includeSpecialChars) {
51+
setIncludeLowercase(true)
52+
return
53+
}
54+
generatePassword()
55+
}, [passwordLength, includeUppercase, includeLowercase, includeNumbers, includeSpecialChars])
1656

1757
const onChangePasswordLength = (value: any) => {
1858
setPasswordLength(value)
1959
}
2060

61+
const handleCopy = () => {
62+
setCopied(true)
63+
setTimeout(() => {
64+
setCopied(false)
65+
}, 1000)
66+
}
67+
68+
const getPasswordStrength = () => {
69+
if (passwordLength < 8) {
70+
return { text: 'Too short', color: 'red' }
71+
}
72+
73+
const hasUppercase = /[A-Z]/.test(password)
74+
const hasLowercase = /[a-z]/.test(password)
75+
const hasNumber = /[0-9]/.test(password)
76+
const hasSpecialChar = /[!@#$%^&*()_+\-=\[\]{}|;:,.<>?]/.test(password)
77+
78+
const categoriesPresent = [hasUppercase, hasLowercase, hasNumber, hasSpecialChar].filter(Boolean).length
79+
80+
if (categoriesPresent === 4) {
81+
return { text: 'Hard', color: 'green' }
82+
} else if (categoriesPresent === 3) {
83+
return { text: 'Medium', color: 'orange' }
84+
} else {
85+
return { text: 'Weak', color: 'red' }
86+
}
87+
}
88+
2189
return (
2290
<div className="password-wrapper">
2391
<div className="gif">
@@ -31,15 +99,19 @@ const PasswordGenerator = () => {
3199
</div>
32100
<div className="password-input-wrapper">
33101
<div className="password-field">
34-
<input type="text" placeholder="your password" value="B9QI4PDBYY" />
35-
<img src={refreshIcon} alt="refresh the password" />
102+
<input type="text" placeholder="your password" value={password} readOnly />
103+
<img src={refreshIcon} alt="refresh the password" onClick={generatePassword} style={{ cursor: 'pointer' }} />
36104
</div>
37-
<button className="copy-btn">
38-
<img src={copyIcon} alt="copy password" />
39-
Copy
40-
</button>
105+
<CopyToClipboard text={password} onCopy={handleCopy}>
106+
<button className="copy-btn">
107+
<img src={copyIcon} alt="copy password" />
108+
{copied ? 'Copied' : 'Copy'}
109+
</button>
110+
</CopyToClipboard>
41111
</div>
42-
<span className="fw-500">Weak</span>
112+
<span className="fw-500" style={{ color: getPasswordStrength().color }}>
113+
{getPasswordStrength().text}
114+
</span>
43115
<div className="slider">
44116
<div>
45117
<label id="slider-label">Password Length: </label>
@@ -54,14 +126,33 @@ const PasswordGenerator = () => {
54126
/>
55127
</div>
56128
<div className="elements">
57-
<Checkbox id="uppercase" label="Uppercase" checked={true} name="upper" />
58-
<Checkbox id="lowercase" label="Lowercase" checked={false} name="lower" />
59-
<Checkbox id="numbers" label="Numbers" checked={false} name="numbers" />
129+
<Checkbox
130+
id="uppercase"
131+
label="Uppercase"
132+
checked={includeUppercase}
133+
name="upper"
134+
onChange={(e: any) => setIncludeUppercase(e.target.checked)}
135+
/>
136+
<Checkbox
137+
id="lowercase"
138+
label="Lowercase"
139+
checked={includeLowercase}
140+
name="lower"
141+
onChange={(e: any) => setIncludeLowercase(e.target.checked)}
142+
/>
143+
<Checkbox
144+
id="numbers"
145+
label="Numbers"
146+
checked={includeNumbers}
147+
name="numbers"
148+
onChange={(e: any) => setIncludeNumbers(e.target.checked)}
149+
/>
60150
<Checkbox
61151
id="special chars"
62152
label="Special Characters"
63-
checked={true}
153+
checked={includeSpecialChars}
64154
name="specialChars"
155+
onChange={(e: any) => setIncludeSpecialChars(e.target.checked)}
65156
/>
66157
</div>
67158
</div>

0 commit comments

Comments
 (0)