Spaces:
Running
Running
| import React, { useState } from 'react'; | |
| import { | |
| Dialog, | |
| DialogTitle, | |
| DialogContent, | |
| DialogActions, | |
| Button, | |
| TextField, | |
| Alert, | |
| CircularProgress, | |
| InputAdornment, | |
| IconButton | |
| } from '@mui/material'; | |
| import { Visibility, VisibilityOff } from '@mui/icons-material'; | |
| import { changePassword } from '../api/client'; | |
| const ChangePasswordModal = ({ open, onClose }) => { | |
| const [oldPassword, setOldPassword] = useState(''); | |
| const [newPassword, setNewPassword] = useState(''); | |
| const [confirmPassword, setConfirmPassword] = useState(''); | |
| const [loading, setLoading] = useState(false); | |
| const [error, setError] = useState(null); | |
| const [success, setSuccess] = useState(false); | |
| const [showOldPassword, setShowOldPassword] = useState(false); | |
| const [showNewPassword, setShowNewPassword] = useState(false); | |
| const [showConfirmPassword, setShowConfirmPassword] = useState(false); | |
| const handleSubmit = async (e) => { | |
| e.preventDefault(); | |
| setError(null); | |
| setSuccess(false); | |
| if (newPassword !== confirmPassword) { | |
| setError("New passwords do not match"); | |
| return; | |
| } | |
| if (newPassword.length < 6) { | |
| setError("Password must be at least 6 characters"); | |
| return; | |
| } | |
| setLoading(true); | |
| try { | |
| await changePassword(oldPassword, newPassword); | |
| setSuccess(true); | |
| setOldPassword(''); | |
| setNewPassword(''); | |
| setConfirmPassword(''); | |
| setTimeout(() => { | |
| onClose(); | |
| setSuccess(false); | |
| }, 1500); | |
| } catch (err) { | |
| console.error(err); | |
| setError(err.response?.data?.detail || "Failed to change password"); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| const handleClose = () => { | |
| setError(null); | |
| setSuccess(false); | |
| onClose(); | |
| }; | |
| return ( | |
| <Dialog open={open} onClose={handleClose} maxWidth="sm" fullWidth> | |
| <DialogTitle>Change Password</DialogTitle> | |
| <form onSubmit={handleSubmit}> | |
| <DialogContent> | |
| {error && <Alert severity="error" sx={{ mb: 2 }}>{error}</Alert>} | |
| {success && <Alert severity="success" sx={{ mb: 2 }}>Password changed successfully!</Alert>} | |
| <TextField | |
| margin="dense" | |
| label="Current Password" | |
| type={showOldPassword ? 'text' : 'password'} | |
| fullWidth | |
| value={oldPassword} | |
| onChange={(e) => setOldPassword(e.target.value)} | |
| required | |
| disabled={loading || success} | |
| InputProps={{ | |
| endAdornment: ( | |
| <InputAdornment position="end"> | |
| <IconButton | |
| onClick={() => setShowOldPassword(!showOldPassword)} | |
| edge="end" | |
| > | |
| {showOldPassword ? <VisibilityOff /> : <Visibility />} | |
| </IconButton> | |
| </InputAdornment> | |
| ) | |
| }} | |
| /> | |
| <TextField | |
| margin="dense" | |
| label="New Password" | |
| type={showNewPassword ? 'text' : 'password'} | |
| fullWidth | |
| value={newPassword} | |
| onChange={(e) => setNewPassword(e.target.value)} | |
| required | |
| disabled={loading || success} | |
| InputProps={{ | |
| endAdornment: ( | |
| <InputAdornment position="end"> | |
| <IconButton | |
| onClick={() => setShowNewPassword(!showNewPassword)} | |
| edge="end" | |
| > | |
| {showNewPassword ? <VisibilityOff /> : <Visibility />} | |
| </IconButton> | |
| </InputAdornment> | |
| ) | |
| }} | |
| /> | |
| <TextField | |
| margin="dense" | |
| label="Confirm New Password" | |
| type={showConfirmPassword ? 'text' : 'password'} | |
| fullWidth | |
| value={confirmPassword} | |
| onChange={(e) => setConfirmPassword(e.target.value)} | |
| required | |
| disabled={loading || success} | |
| InputProps={{ | |
| endAdornment: ( | |
| <InputAdornment position="end"> | |
| <IconButton | |
| onClick={() => setShowConfirmPassword(!showConfirmPassword)} | |
| edge="end" | |
| > | |
| {showConfirmPassword ? <VisibilityOff /> : <Visibility />} | |
| </IconButton> | |
| </InputAdornment> | |
| ) | |
| }} | |
| /> | |
| </DialogContent> | |
| <DialogActions> | |
| <Button onClick={handleClose} disabled={loading}>Cancel</Button> | |
| <Button type="submit" variant="contained" disabled={loading || success} startIcon={loading ? <CircularProgress size={20} /> : null}> | |
| {loading ? 'Updating...' : 'Update Password'} | |
| </Button> | |
| </DialogActions> | |
| </form> | |
| </Dialog> | |
| ); | |
| }; | |
| export default ChangePasswordModal; | |