import React, { FormEventHandler, useCallback, useState, useEffect } from 'react'; import { Box, Text, Button, Overlay, OverlayBackdrop, OverlayCenter, Dialog, Header, Icon, IconButton, Icons, config, Spinner, color, } from 'folds'; import FocusTrap from 'focus-trap-react'; import AuthDict from 'matrix-js-sdk'; import { SequenceCard } from '../../../components/sequence-card'; import { SequenceCardStyle } from '../styles.css'; import { SettingTile } from '../../../components/setting-tile'; import { PasswordInput } from '../../../components/password-input'; import { ConfirmPasswordMatch } from '../../../components/ConfirmPasswordMatch'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback'; import { ActionUIA, ActionUIAFlowsLoader } from '../../../components/ActionUIA'; import { changePassword, ChangePasswordResult } from '../../../utils/changePassword'; import { useCapabilities } from '../../../hooks/useCapabilities'; function ChangePasswordSuccess({ onClose }: { onClose: () => void }) { return ( }>
Password Changed
Your password has been successfully changed. Your other devices may need to be re-verified.
); } type ChangePasswordFormProps = { onCancel: () => void; onSuccess: () => void; }; function ChangePasswordForm({ onCancel, onSuccess }: ChangePasswordFormProps) { const mx = useMatrixClient(); const [formData, setFormData] = useState<{ newPassword: string; logoutDevices: boolean } | null>( null ); const [changePasswordState, handleChangePassword] = useAsyncCallback< ChangePasswordResult, Error, [AuthDict | undefined, string, boolean] >( useCallback( async (authDict, newPassword, logoutDevices) => changePassword(mx, authDict, newPassword, logoutDevices), [mx] ) ); const [ongoingAuthData, changePasswordResult] = changePasswordState.status === AsyncStatus.Success ? changePasswordState.data : [undefined, undefined]; const handleFormSubmit: FormEventHandler = (evt) => { evt.preventDefault(); const formDataObj = new FormData(evt.currentTarget); const newPassword = formDataObj.get('newPassword') as string; const confirmPassword = formDataObj.get('confirmPassword') as string; const logoutDevices = formDataObj.get('logoutDevices') === 'on'; if (!newPassword || !confirmPassword) return; if (newPassword !== confirmPassword) return; // Store form data for UIA completion const formState = { newPassword, logoutDevices }; setFormData(formState); // Just call the async callback - don't handle the result here // The component state will automatically update and handle UIA vs success handleChangePassword(undefined, newPassword, logoutDevices); }; // Handle successful completion useEffect(() => { if (changePasswordResult && !ongoingAuthData) { onSuccess(); } }, [changePasswordResult, ongoingAuthData, onSuccess]); // Don't show success dialog in this component - let parent handle it if (changePasswordResult && !ongoingAuthData) { return null; // Success state handled by parent component } // Show UIA flow if we have auth data if (ongoingAuthData) { return ( ( }> This server requires authentication methods that are not supported by this client. )} > {(ongoingFlow) => ( { if (formData) { handleChangePassword(authDict, formData.newPassword, formData.logoutDevices); } else { onCancel(); } }} onCancel={onCancel} /> )} ); } const isLoading = changePasswordState.status === AsyncStatus.Loading; const error = changePasswordState.status === AsyncStatus.Error ? changePasswordState.error : undefined; return ( }>
Change Password
Enter your new password. You may need to re-verify your other devices after changing your password. {(match, doMatch, passRef, confPassRef) => ( <> New Password Confirm New Password )} Sign out all other devices Recommended for security. Unchecking this may leave your other devices logged in. {error && ( Failed to change password: {error.message} )}
); } export function ChangePassword() { const [showDialog, setShowDialog] = useState(false); const [showSuccess, setShowSuccess] = useState(false); const capabilities = useCapabilities(); // Check if password change is disabled by server capabilities const disableChangePassword = capabilities['m.change_password']?.enabled === false; const handleOpenDialog = () => setShowDialog(true); const handleCloseDialog = () => { setShowDialog(false); setShowSuccess(false); }; const handleSuccess = () => { setShowDialog(false); setShowSuccess(true); }; return ( <> Password Change } /> {showDialog && } {showSuccess && } ); }