113 lines
4.3 KiB
TypeScript
113 lines
4.3 KiB
TypeScript
import React from 'react';
|
|
import { defineMessages, useIntl } from 'react-intl';
|
|
|
|
import { changePassword } from 'soapbox/actions/security';
|
|
import { Button, Card, CardBody, CardHeader, CardTitle, Column, Form, FormActions, FormGroup, Input } from 'soapbox/components/ui';
|
|
import { useAppDispatch, useFeatures } from 'soapbox/hooks';
|
|
import toast from 'soapbox/toast';
|
|
|
|
import PasswordIndicator from '../verification/components/password-indicator';
|
|
|
|
const messages = defineMessages({
|
|
updatePasswordSuccess: { id: 'security.update_password.success', defaultMessage: 'Password successfully updated.' },
|
|
updatePasswordFail: { id: 'security.update_password.fail', defaultMessage: 'Update password failed.' },
|
|
oldPasswordFieldLabel: { id: 'security.fields.old_password.label', defaultMessage: 'Current password' },
|
|
newPasswordFieldLabel: { id: 'security.fields.new_password.label', defaultMessage: 'New password' },
|
|
confirmationFieldLabel: { id: 'security.fields.password_confirmation.label', defaultMessage: 'New password (again)' },
|
|
header: { id: 'edit_password.header', defaultMessage: 'Change Password' },
|
|
submit: { id: 'security.submit', defaultMessage: 'Save changes' },
|
|
cancel: { id: 'common.cancel', defaultMessage: 'Cancel' },
|
|
});
|
|
|
|
const initialState = { currentPassword: '', newPassword: '', newPasswordConfirmation: '' };
|
|
|
|
const EditPassword = () => {
|
|
const intl = useIntl();
|
|
const dispatch = useAppDispatch();
|
|
const { passwordRequirements } = useFeatures();
|
|
|
|
const [state, setState] = React.useState(initialState);
|
|
const [isLoading, setLoading] = React.useState(false);
|
|
const [hasValidPassword, setHasValidPassword] = React.useState<boolean>(passwordRequirements ? false : true);
|
|
|
|
const { currentPassword, newPassword, newPasswordConfirmation } = state;
|
|
|
|
const resetState = () => setState(initialState);
|
|
|
|
const handleInputChange: React.ChangeEventHandler<HTMLInputElement> = React.useCallback((event) => {
|
|
event.persist();
|
|
|
|
setState((prevState) => ({ ...prevState, [event.target.name]: event.target.value }));
|
|
}, []);
|
|
|
|
const handleSubmit = React.useCallback(() => {
|
|
setLoading(true);
|
|
dispatch(changePassword(currentPassword, newPassword, newPasswordConfirmation)).then(() => {
|
|
resetState();
|
|
toast.success(intl.formatMessage(messages.updatePasswordSuccess));
|
|
|
|
}).finally(() => {
|
|
setLoading(false);
|
|
}).catch(() => {
|
|
resetState();
|
|
toast.error(intl.formatMessage(messages.updatePasswordFail));
|
|
});
|
|
}, [currentPassword, newPassword, newPasswordConfirmation, dispatch, intl]);
|
|
|
|
return (
|
|
<Column label={intl.formatMessage(messages.header)} transparent withHeader={false}>
|
|
<Card variant='rounded'>
|
|
<CardHeader backHref='/settings'>
|
|
<CardTitle title={intl.formatMessage(messages.header)} />
|
|
</CardHeader>
|
|
|
|
<CardBody>
|
|
<Form onSubmit={handleSubmit}>
|
|
<FormGroup labelText={intl.formatMessage(messages.oldPasswordFieldLabel)}>
|
|
<Input
|
|
type='password'
|
|
name='currentPassword'
|
|
onChange={handleInputChange}
|
|
value={currentPassword}
|
|
/>
|
|
</FormGroup>
|
|
|
|
<FormGroup labelText={intl.formatMessage(messages.newPasswordFieldLabel)}>
|
|
<Input
|
|
type='password'
|
|
name='newPassword'
|
|
onChange={handleInputChange}
|
|
value={newPassword}
|
|
/>
|
|
|
|
{passwordRequirements && (
|
|
<PasswordIndicator password={newPassword} onChange={setHasValidPassword} />
|
|
)}
|
|
</FormGroup>
|
|
|
|
<FormGroup labelText={intl.formatMessage(messages.confirmationFieldLabel)}>
|
|
<Input
|
|
type='password'
|
|
name='newPasswordConfirmation'
|
|
onChange={handleInputChange}
|
|
value={newPasswordConfirmation}
|
|
/>
|
|
</FormGroup>
|
|
|
|
<FormActions>
|
|
<Button to='/settings' theme='tertiary'>
|
|
{intl.formatMessage(messages.cancel)}
|
|
</Button>
|
|
|
|
<Button type='submit' theme='primary' disabled={isLoading || !hasValidPassword}>
|
|
{intl.formatMessage(messages.submit)}
|
|
</Button>
|
|
</FormActions>
|
|
</Form>
|
|
</CardBody>
|
|
</Card>
|
|
</Column>
|
|
);
|
|
};
|
|
|
|
export default EditPassword;
|