Initial commit - frontend
This commit is contained in:
188
src/components/ChangePasswordDrawer.tsx
Normal file
188
src/components/ChangePasswordDrawer.tsx
Normal file
@@ -0,0 +1,188 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
Drawer,
|
||||
Box,
|
||||
Typography,
|
||||
TextField,
|
||||
Button,
|
||||
Alert,
|
||||
IconButton,
|
||||
LinearProgress
|
||||
} from '@mui/material';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import { encrypt } from '@/app/utils/encryption';
|
||||
import { getPasswordStrength } from '@/app/utils/passwordStrength';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
import Cookies from 'js-cookie';
|
||||
|
||||
const ChangePasswordDrawer = ({
|
||||
open,
|
||||
onClose
|
||||
}: {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}) => {
|
||||
const { username, authToken } = useAuth();
|
||||
//console.log('🧪 username:', username);
|
||||
//console.log('🧪 authToken:', authToken);
|
||||
|
||||
const [currentPassword, setCurrentPassword] = useState('');
|
||||
const [newPassword, setNewPassword] = useState('');
|
||||
const [confirmPassword, setConfirmPassword] = useState('');
|
||||
const [message, setMessage] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
|
||||
|
||||
const strength = getPasswordStrength(newPassword);
|
||||
const strengthValue = strength === 'Weak' ? 30 : strength === 'Medium' ? 60 : 100;
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) resetForm();
|
||||
}, [open]);
|
||||
|
||||
const resetForm = () => {
|
||||
setCurrentPassword('');
|
||||
setNewPassword('');
|
||||
setConfirmPassword('');
|
||||
setMessage('');
|
||||
setError('');
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setMessage('');
|
||||
setError('');
|
||||
|
||||
if (!username) {
|
||||
setError('User not authenticated.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (newPassword !== confirmPassword) {
|
||||
setError('New passwords do not match.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/auth/change-password', {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({
|
||||
currentPassword: encrypt(currentPassword),
|
||||
newPassword: encrypt(newPassword),
|
||||
}),
|
||||
});
|
||||
|
||||
const text = await res.text();
|
||||
if (res.ok) {
|
||||
setMessage(text);
|
||||
} else {
|
||||
setError(text);
|
||||
}
|
||||
} catch (err) {
|
||||
setError('An unexpected error occurred.');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<Drawer anchor="left" open={open} onClose={onClose} transitionDuration={300}>
|
||||
<Box sx={{ width: 350, p: 3 }}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 2 }}>
|
||||
<Typography variant="h6">Change Password</Typography>
|
||||
<IconButton onClick={onClose}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
type="password"
|
||||
label="Current Password"
|
||||
fullWidth
|
||||
margin="normal"
|
||||
value={currentPassword}
|
||||
onChange={(e) => setCurrentPassword(e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
<TextField
|
||||
type="password"
|
||||
label="New Password"
|
||||
fullWidth
|
||||
margin="normal"
|
||||
value={newPassword}
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
{/* Password Strength Bar */}
|
||||
<Box sx={{ mt: 1 }}>
|
||||
<Typography variant="caption">Strength: {strength}</Typography>
|
||||
<LinearProgress
|
||||
variant="determinate"
|
||||
value={strengthValue}
|
||||
color={
|
||||
strength === 'Strong'
|
||||
? 'success'
|
||||
: strength === 'Medium'
|
||||
? 'warning'
|
||||
: 'error'
|
||||
}
|
||||
sx={{ height: 6, borderRadius: 2, mt: 0.5 }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<TextField
|
||||
type="password"
|
||||
label="Confirm New Password"
|
||||
fullWidth
|
||||
margin="normal"
|
||||
value={confirmPassword}
|
||||
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
fullWidth
|
||||
sx={{ mt: 2 }}
|
||||
disabled={username === 'testuser'}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
|
||||
{username === 'testuser' && (
|
||||
<Box
|
||||
sx={{
|
||||
mt: 1,
|
||||
backgroundColor: '#f5f5f5',
|
||||
p: 1.5,
|
||||
borderRadius: 1,
|
||||
borderLeft: '4px solid #0288d1',
|
||||
fontSize: '0.875rem',
|
||||
color: '#333',
|
||||
}}
|
||||
>
|
||||
Password changes are disabled for this user.
|
||||
</Box>
|
||||
)}
|
||||
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
{message && <Alert severity="success" sx={{ mt: 2 }}>{message}</Alert>}
|
||||
{error && <Alert severity="error" sx={{ mt: 2 }}>{error}</Alert>}
|
||||
</Box>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChangePasswordDrawer;
|
||||
Reference in New Issue
Block a user