import { useEffect, useState } from 'react' import { Trans, useTranslation } from 'react-i18next' import { getUserFacingMessage, getErrorMessageKey, postJSON, } from '../../../infrastructure/fetch-json' import getMeta from '../../../utils/meta' import useAsync from '../../../shared/hooks/use-async' import OLButton from '@/features/ui/components/ol/ol-button' import OLNotification from '@/features/ui/components/ol/ol-notification' import OLFormGroup from '@/features/ui/components/ol/ol-form-group' import OLFormLabel from '@/features/ui/components/ol/ol-form-label' import OLFormControl from '@/features/ui/components/ol/ol-form-control' import OLFormText from '@/features/ui/components/ol/ol-form-text' type PasswordUpdateResult = { message?: { text: string } } function PasswordSection() { const { t } = useTranslation() const hideChangePassword = getMeta('ol-cannot-change-password') return ( <>

{t('change_password')}

{hideChangePassword ? ( ) : ( )} ) } function CanOnlyLogInThroughSSO() { return (

, ]} />

) } function PasswordInnerSection() { const { t } = useTranslation() const { isOverleaf } = getMeta('ol-ExposedSettings') const isExternalAuthenticationSystemUsed = getMeta( 'ol-isExternalAuthenticationSystemUsed' ) const hasPassword = getMeta('ol-hasPassword') if (isExternalAuthenticationSystemUsed && !isOverleaf) { return

{t('password_managed_externally')}

} if (!hasPassword) { return (

{t('no_existing_password')}

) } return } function PasswordForm() { const { t } = useTranslation() const passwordStrengthOptions = getMeta('ol-passwordStrengthOptions') const [currentPassword, setCurrentPassword] = useState('') const [newPassword1, setNewPassword1] = useState('') const [newPassword2, setNewPassword2] = useState('') const { isLoading, isSuccess, isError, data, error, runAsync } = useAsync() const [isNewPasswordValid, setIsNewPasswordValid] = useState(false) const [isFormValid, setIsFormValid] = useState(false) const handleCurrentPasswordChange = ( event: React.ChangeEvent ) => { setCurrentPassword(event.target.value) } const handleNewPassword1Change = ( event: React.ChangeEvent ) => { setNewPassword1(event.target.value) setIsNewPasswordValid(event.target.validity.valid) } const handleNewPassword2Change = ( event: React.ChangeEvent ) => { setNewPassword2(event.target.value) } useEffect(() => { setIsFormValid( !!currentPassword && isNewPasswordValid && newPassword1 === newPassword2 ) }, [currentPassword, newPassword1, newPassword2, isNewPasswordValid]) const handleSubmit = (event: React.FormEvent) => { event.preventDefault() if (!isFormValid) { return } runAsync( postJSON('/user/password/update', { body: { currentPassword, newPassword1, newPassword2, }, }) ).catch(() => {}) } return (
{isSuccess && data?.message?.text ? ( ) : null} {isError ? ( , ]} /> . {t('use_a_different_password')}. ) : getErrorMessageKey(error) === 'password-contains-email' ? ( <> {t('invalid_password_contains_email')}.{' '} {t('use_a_different_password')}. ) : getErrorMessageKey(error) === 'password-too-similar' ? ( <> {t('invalid_password_too_similar')}.{' '} {t('use_a_different_password')}. ) : ( getUserFacingMessage(error) ?? '' ) } /> ) : null} {t('change')} ) } type PasswordFormGroupProps = { id: string label: string value: string handleChange: (event: React.ChangeEvent) => void minLength?: number validationMessage?: string autoComplete?: string } function PasswordFormGroup({ id, label, value, handleChange, minLength, validationMessage: parentValidationMessage, autoComplete, }: PasswordFormGroupProps) { const [validationMessage, setValidationMessage] = useState('') const [hadInteraction, setHadInteraction] = useState(false) const handleInvalid = (event: React.InvalidEvent) => { event.preventDefault() } const handleChangeAndValidity = ( event: React.ChangeEvent ) => { handleChange(event) setHadInteraction(true) setValidationMessage(event.target.validationMessage) } const isInvalid = Boolean( hadInteraction && (parentValidationMessage || validationMessage) ) return ( {label} {isInvalid && ( {parentValidationMessage || validationMessage} )} ) } export default PasswordSection