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 (
}>
);
}
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 (
(
}>
)}
>
{(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 (
}>
);
}
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 && }
>
);
}