forked from AryanVBW/Portal
-
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.
Merge branch 'AryanVBW:main' into main
- Loading branch information
Showing
4 changed files
with
223 additions
and
12 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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,145 @@ | ||
import React, { useState } from 'react'; | ||
import { X, Lock } from 'lucide-react'; | ||
import { toast } from 'react-toastify'; | ||
import { changePassword } from '../services/auth'; | ||
import { User } from '../types/auth'; | ||
|
||
interface ChangePasswordModalProps { | ||
user: User; | ||
isOpen: boolean; | ||
onClose: () => void; | ||
} | ||
|
||
export default function ChangePasswordModal({ user, isOpen, onClose }: ChangePasswordModalProps) { | ||
const [formData, setFormData] = useState({ | ||
currentPassword: '', | ||
newPassword: '', | ||
confirmPassword: '', | ||
}); | ||
const [loading, setLoading] = useState(false); | ||
|
||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
const { name, value } = e.target; | ||
setFormData(prev => ({ ...prev, [name]: value })); | ||
}; | ||
|
||
const handleSubmit = async (e: React.FormEvent) => { | ||
e.preventDefault(); | ||
|
||
if (formData.newPassword !== formData.confirmPassword) { | ||
toast.error('New passwords do not match'); | ||
return; | ||
} | ||
|
||
setLoading(true); | ||
try { | ||
await changePassword(user.id, formData.currentPassword, formData.newPassword); | ||
toast.success('Password changed successfully'); | ||
onClose(); | ||
// Clear form data | ||
setFormData({ | ||
currentPassword: '', | ||
newPassword: '', | ||
confirmPassword: '', | ||
}); | ||
} catch (error: any) { | ||
toast.error(error.message); | ||
} finally { | ||
setLoading(false); | ||
} | ||
}; | ||
|
||
if (!isOpen) return null; | ||
|
||
return ( | ||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> | ||
<div className="bg-white rounded-lg w-full max-w-md p-6 relative"> | ||
<button | ||
onClick={onClose} | ||
className="absolute top-4 right-4 text-gray-500 hover:text-gray-700" | ||
> | ||
<X className="h-5 w-5" /> | ||
</button> | ||
|
||
<div className="flex items-center space-x-2 mb-6"> | ||
<Lock className="h-6 w-6 text-indigo-600" /> | ||
<h2 className="text-xl font-semibold">Change Password</h2> | ||
</div> | ||
|
||
<form onSubmit={handleSubmit} className="space-y-4"> | ||
<div> | ||
<label htmlFor="currentPassword" className="block text-sm font-medium text-gray-700 mb-1"> | ||
Current Password | ||
</label> | ||
<input | ||
type="password" | ||
id="currentPassword" | ||
name="currentPassword" | ||
value={formData.currentPassword} | ||
onChange={handleChange} | ||
required | ||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" | ||
/> | ||
</div> | ||
|
||
<div> | ||
<label htmlFor="newPassword" className="block text-sm font-medium text-gray-700 mb-1"> | ||
New Password | ||
</label> | ||
<input | ||
type="password" | ||
id="newPassword" | ||
name="newPassword" | ||
value={formData.newPassword} | ||
onChange={handleChange} | ||
required | ||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" | ||
/> | ||
</div> | ||
|
||
<div> | ||
<label htmlFor="confirmPassword" className="block text-sm font-medium text-gray-700 mb-1"> | ||
Confirm New Password | ||
</label> | ||
<input | ||
type="password" | ||
id="confirmPassword" | ||
name="confirmPassword" | ||
value={formData.confirmPassword} | ||
onChange={handleChange} | ||
required | ||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" | ||
/> | ||
</div> | ||
|
||
<div className="text-sm text-gray-600"> | ||
Password must: | ||
<ul className="list-disc list-inside mt-1"> | ||
<li>Be at least 8 characters long</li> | ||
<li>Contain at least one uppercase letter</li> | ||
<li>Contain at least one number</li> | ||
<li>Contain at least one special character (!@#$%^&*)</li> | ||
</ul> | ||
</div> | ||
|
||
<div className="flex justify-end space-x-3 mt-6"> | ||
<button | ||
type="button" | ||
onClick={onClose} | ||
className="px-4 py-2 text-sm font-medium text-gray-700 hover:text-gray-900" | ||
> | ||
Cancel | ||
</button> | ||
<button | ||
type="submit" | ||
disabled={loading} | ||
className="px-4 py-2 bg-indigo-600 text-white rounded-md text-sm font-medium hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50 disabled:cursor-not-allowed" | ||
> | ||
{loading ? 'Changing Password...' : 'Change Password'} | ||
</button> | ||
</div> | ||
</form> | ||
</div> | ||
</div> | ||
); | ||
} |
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 |
---|---|---|
|
@@ -45,4 +45,52 @@ export const signOut = async (): Promise<void> => { | |
|
||
export const getCurrentSession = (): User | null => { | ||
return getCurrentUser(); | ||
}; | ||
|
||
export const changePassword = async (userId: string, currentPassword: string, newPassword: string): Promise<void> => { | ||
try { | ||
const users = getUsers(); | ||
const user = users.find(u => u.id === userId); | ||
|
||
if (!user) { | ||
throw new Error('User not found'); | ||
} | ||
|
||
// For demo purposes, we're only checking the super admin's password | ||
if (user.email === '[email protected]' && currentPassword !== 'Vivek@2024') { | ||
throw new Error('Current password is incorrect'); | ||
} | ||
|
||
// In a real app, you would: | ||
// 1. Verify the current password hash matches | ||
// 2. Hash the new password | ||
// 3. Update the password in the database | ||
|
||
// For this demo, we'll just validate the password format | ||
if (newPassword.length < 8) { | ||
throw new Error('Password must be at least 8 characters long'); | ||
} | ||
|
||
if (!/[A-Z]/.test(newPassword)) { | ||
throw new Error('Password must contain at least one uppercase letter'); | ||
} | ||
|
||
if (!/[0-9]/.test(newPassword)) { | ||
throw new Error('Password must contain at least one number'); | ||
} | ||
|
||
if (!/[!@#$%^&*]/.test(newPassword)) { | ||
throw new Error('Password must contain at least one special character (!@#$%^&*)'); | ||
} | ||
|
||
// Update the password (in a real app, this would be hashed) | ||
if (user.email === '[email protected]') { | ||
// For demo purposes, we're only actually changing the super admin's password | ||
user.password = newPassword; | ||
const updatedUsers = users.map(u => u.id === userId ? user : u); | ||
localStorage.setItem('users', JSON.stringify(updatedUsers)); | ||
} | ||
} catch (error: any) { | ||
throw new Error(error.message); | ||
} | ||
}; |