Convert general user to functional component (#12856)

This commit is contained in:
David Baker 2024-08-01 16:28:11 +01:00 committed by GitHub
parent 127051892d
commit 9cd0c247a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React from "react"; import React, { useCallback, useContext, useEffect } from "react";
import { HTTPError } from "matrix-js-sdk/src/matrix"; import { HTTPError } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
@ -34,41 +34,77 @@ import { SettingsSection } from "../../shared/SettingsSection";
import SettingsSubsection, { SettingsSubsectionText } from "../../shared/SettingsSubsection"; import SettingsSubsection, { SettingsSubsectionText } from "../../shared/SettingsSubsection";
import { SDKContext } from "../../../../../contexts/SDKContext"; import { SDKContext } from "../../../../../contexts/SDKContext";
import UserPersonalInfoSettings from "../../UserPersonalInfoSettings"; import UserPersonalInfoSettings from "../../UserPersonalInfoSettings";
import { useMatrixClientContext } from "../../../../../contexts/MatrixClientContext";
interface IProps { interface IProps {
closeSettingsFn: () => void; closeSettingsFn: () => void;
} }
interface IState { interface AccountSectionProps {
canChangePassword: boolean; canChangePassword: boolean;
idServerName?: string; onPasswordChangeError: (e: Error) => void;
externalAccountManagementUrl?: string; onPasswordChanged: () => void;
canMake3pidChanges: boolean;
canSetDisplayName: boolean;
canSetAvatar: boolean;
} }
export default class GeneralUserSettingsTab extends React.Component<IProps, IState> { const AccountSection: React.FC<AccountSectionProps> = ({
public static contextType = SDKContext; canChangePassword,
public context!: React.ContextType<typeof SDKContext>; onPasswordChangeError,
onPasswordChanged,
}) => {
if (!canChangePassword) return <></>;
public constructor(props: IProps, context: React.ContextType<typeof SDKContext>) { return (
super(props, context); <>
this.context = context; <SettingsSubsection
heading={_t("settings|general|account_section")}
stretchContent
data-testid="accountSection"
>
<SettingsSubsectionText>{_t("settings|general|password_change_section")}</SettingsSubsectionText>
<ChangePassword
className="mx_GeneralUserSettingsTab_section--account_changePassword"
rowClassName=""
buttonKind="primary"
onError={onPasswordChangeError}
onFinished={onPasswordChanged}
/>
</SettingsSubsection>
</>
);
};
this.state = { interface ManagementSectionProps {
canChangePassword: false, onDeactivateClicked: () => void;
canMake3pidChanges: false, }
canSetDisplayName: false,
canSetAvatar: false,
};
this.getCapabilities(); const ManagementSection: React.FC<ManagementSectionProps> = ({ onDeactivateClicked }) => {
} return (
<SettingsSection heading={_t("settings|general|deactivate_section")}>
<SettingsSubsection
heading={_t("settings|general|account_management_section")}
data-testid="account-management-section"
description={_t("settings|general|deactivate_warning")}
>
<AccessibleButton onClick={onDeactivateClicked} kind="danger">
{_t("settings|general|deactivate_section")}
</AccessibleButton>
</SettingsSubsection>
</SettingsSection>
);
};
private async getCapabilities(): Promise<void> { const GeneralUserSettingsTab: React.FC<IProps> = ({ closeSettingsFn }) => {
const cli = this.context.client!; const [externalAccountManagementUrl, setExternalAccountManagementUrl] = React.useState<string | undefined>();
const [canMake3pidChanges, setCanMake3pidChanges] = React.useState<boolean>(false);
const [canSetDisplayName, setCanSetDisplayName] = React.useState<boolean>(false);
const [canSetAvatar, setCanSetAvatar] = React.useState<boolean>(false);
const [canChangePassword, setCanChangePassword] = React.useState<boolean>(false);
const cli = useMatrixClientContext();
const sdkContext = useContext(SDKContext);
useEffect(() => {
(async () => {
const capabilities = (await cli.getCapabilities()) ?? {}; const capabilities = (await cli.getCapabilities()) ?? {};
const changePasswordCap = capabilities["m.change_password"]; const changePasswordCap = capabilities["m.change_password"];
@ -77,27 +113,27 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
// the enabled flag value. // the enabled flag value.
const canChangePassword = !changePasswordCap || changePasswordCap["enabled"] !== false; const canChangePassword = !changePasswordCap || changePasswordCap["enabled"] !== false;
await this.context.oidcClientStore.readyPromise; // wait for the store to be ready await sdkContext.oidcClientStore.readyPromise; // wait for the store to be ready
const externalAccountManagementUrl = this.context.oidcClientStore.accountManagementEndpoint; const externalAccountManagementUrl = sdkContext.oidcClientStore.accountManagementEndpoint;
// https://spec.matrix.org/v1.7/client-server-api/#m3pid_changes-capability // https://spec.matrix.org/v1.7/client-server-api/#m3pid_changes-capability
// We support as far back as v1.1 which doesn't have m.3pid_changes // We support as far back as v1.1 which doesn't have m.3pid_changes
// so the behaviour for when it is missing has to be assume true // so the behaviour for when it is missing has to be assume true
const canMake3pidChanges = !capabilities["m.3pid_changes"] || capabilities["m.3pid_changes"].enabled === true; const canMake3pidChanges =
!capabilities["m.3pid_changes"] || capabilities["m.3pid_changes"].enabled === true;
const canSetDisplayName = const canSetDisplayName =
!capabilities["m.set_displayname"] || capabilities["m.set_displayname"].enabled === true; !capabilities["m.set_displayname"] || capabilities["m.set_displayname"].enabled === true;
const canSetAvatar = !capabilities["m.set_avatar_url"] || capabilities["m.set_avatar_url"].enabled === true; const canSetAvatar = !capabilities["m.set_avatar_url"] || capabilities["m.set_avatar_url"].enabled === true;
this.setState({ setCanMake3pidChanges(canMake3pidChanges);
canChangePassword, setCanSetDisplayName(canSetDisplayName);
externalAccountManagementUrl, setCanSetAvatar(canSetAvatar);
canMake3pidChanges, setExternalAccountManagementUrl(externalAccountManagementUrl);
canSetDisplayName, setCanChangePassword(canChangePassword);
canSetAvatar, })();
}); }, [cli, sdkContext.oidcClientStore]);
}
private onPasswordChangeError = (err: Error): void => { const onPasswordChangeError = useCallback((err: Error): void => {
logger.error("Failed to change password: " + err); logger.error("Failed to change password: " + err);
let underlyingError = err; let underlyingError = err;
@ -127,85 +163,49 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
title: _t("settings|general|error_password_change_title"), title: _t("settings|general|error_password_change_title"),
description: errorMessageToDisplay, description: errorMessageToDisplay,
}); });
}; }, []);
private onPasswordChanged = (): void => { const onPasswordChanged = useCallback((): void => {
const description = _t("settings|general|password_change_success"); const description = _t("settings|general|password_change_success");
// TODO: Figure out a design that doesn't involve replacing the current dialog // TODO: Figure out a design that doesn't involve replacing the current dialog
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: _t("common|success"), title: _t("common|success"),
description, description,
}); });
}; }, []);
private onDeactivateClicked = (): void => { const onDeactivateClicked = useCallback((): void => {
Modal.createDialog(DeactivateAccountDialog, { Modal.createDialog(DeactivateAccountDialog, {
onFinished: (success) => { onFinished: (success) => {
if (success) this.props.closeSettingsFn(); if (success) closeSettingsFn();
}, },
}); });
}; }, [closeSettingsFn]);
private renderAccountSection(): JSX.Element | undefined {
if (!this.state.canChangePassword) return undefined;
return (
<>
<SettingsSubsection
heading={_t("settings|general|account_section")}
stretchContent
data-testid="accountSection"
>
<SettingsSubsectionText>{_t("settings|general|password_change_section")}</SettingsSubsectionText>
<ChangePassword
className="mx_GeneralUserSettingsTab_section--account_changePassword"
rowClassName=""
buttonKind="primary"
onError={this.onPasswordChangeError}
onFinished={this.onPasswordChanged}
/>
</SettingsSubsection>
</>
);
}
private renderManagementSection(): JSX.Element {
// TODO: Improve warning text for account deactivation
return (
<SettingsSection heading={_t("settings|general|deactivate_section")}>
<SettingsSubsection
heading={_t("settings|general|account_management_section")}
data-testid="account-management-section"
description={_t("settings|general|deactivate_warning")}
>
<AccessibleButton onClick={this.onDeactivateClicked} kind="danger">
{_t("settings|general|deactivate_section")}
</AccessibleButton>
</SettingsSubsection>
</SettingsSection>
);
}
public render(): React.ReactNode {
let accountManagementSection: JSX.Element | undefined; let accountManagementSection: JSX.Element | undefined;
const isAccountManagedExternally = !!this.state.externalAccountManagementUrl; const isAccountManagedExternally = Boolean(externalAccountManagementUrl);
if (SettingsStore.getValue(UIFeature.Deactivate) && !isAccountManagedExternally) { if (SettingsStore.getValue(UIFeature.Deactivate) && !isAccountManagedExternally) {
accountManagementSection = this.renderManagementSection(); accountManagementSection = <ManagementSection onDeactivateClicked={onDeactivateClicked} />;
} }
return ( return (
<SettingsTab data-testid="mx_GeneralUserSettingsTab"> <SettingsTab data-testid="mx_GeneralUserSettingsTab">
<SettingsSection> <SettingsSection>
<UserProfileSettings <UserProfileSettings
externalAccountManagementUrl={this.state.externalAccountManagementUrl} externalAccountManagementUrl={externalAccountManagementUrl}
canSetDisplayName={this.state.canSetDisplayName} canSetDisplayName={canSetDisplayName}
canSetAvatar={this.state.canSetAvatar} canSetAvatar={canSetAvatar}
/>
<UserPersonalInfoSettings canMake3pidChanges={canMake3pidChanges} />
<AccountSection
canChangePassword={canChangePassword}
onPasswordChanged={onPasswordChanged}
onPasswordChangeError={onPasswordChangeError}
/> />
<UserPersonalInfoSettings canMake3pidChanges={this.state.canMake3pidChanges} />
{this.renderAccountSection()}
</SettingsSection> </SettingsSection>
{accountManagementSection} {accountManagementSection}
</SettingsTab> </SettingsTab>
); );
} };
}
export default GeneralUserSettingsTab;