Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Convert general user to functional component (#12856)
Browse files Browse the repository at this point in the history
  • Loading branch information
dbkr authored Aug 1, 2024
1 parent 1270518 commit 9cd0c24
Showing 1 changed file with 122 additions and 122 deletions.
244 changes: 122 additions & 122 deletions src/components/views/settings/tabs/user/GeneralUserSettingsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import React from "react";
import React, { useCallback, useContext, useEffect } from "react";
import { HTTPError } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";

Expand All @@ -34,70 +34,106 @@ import { SettingsSection } from "../../shared/SettingsSection";
import SettingsSubsection, { SettingsSubsectionText } from "../../shared/SettingsSubsection";
import { SDKContext } from "../../../../../contexts/SDKContext";
import UserPersonalInfoSettings from "../../UserPersonalInfoSettings";
import { useMatrixClientContext } from "../../../../../contexts/MatrixClientContext";

interface IProps {
closeSettingsFn: () => void;
}

interface IState {
interface AccountSectionProps {
canChangePassword: boolean;
idServerName?: string;
externalAccountManagementUrl?: string;
canMake3pidChanges: boolean;
canSetDisplayName: boolean;
canSetAvatar: boolean;
onPasswordChangeError: (e: Error) => void;
onPasswordChanged: () => void;
}

export default class GeneralUserSettingsTab extends React.Component<IProps, IState> {
public static contextType = SDKContext;
public context!: React.ContextType<typeof SDKContext>;

public constructor(props: IProps, context: React.ContextType<typeof SDKContext>) {
super(props, context);
this.context = context;

this.state = {
canChangePassword: false,
canMake3pidChanges: false,
canSetDisplayName: false,
canSetAvatar: false,
};

this.getCapabilities();
}

private async getCapabilities(): Promise<void> {
const cli = this.context.client!;

const capabilities = (await cli.getCapabilities()) ?? {};
const changePasswordCap = capabilities["m.change_password"];

// You can change your password so long as the capability isn't explicitly disabled. The implicit
// behaviour is you can change your password when the capability is missing or has not-false as
// the enabled flag value.
const canChangePassword = !changePasswordCap || changePasswordCap["enabled"] !== false;

await this.context.oidcClientStore.readyPromise; // wait for the store to be ready
const externalAccountManagementUrl = this.context.oidcClientStore.accountManagementEndpoint;
// 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
// 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 canSetDisplayName =
!capabilities["m.set_displayname"] || capabilities["m.set_displayname"].enabled === true;
const canSetAvatar = !capabilities["m.set_avatar_url"] || capabilities["m.set_avatar_url"].enabled === true;

this.setState({
canChangePassword,
externalAccountManagementUrl,
canMake3pidChanges,
canSetDisplayName,
canSetAvatar,
});
}
const AccountSection: React.FC<AccountSectionProps> = ({
canChangePassword,
onPasswordChangeError,
onPasswordChanged,
}) => {
if (!canChangePassword) return <></>;

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={onPasswordChangeError}
onFinished={onPasswordChanged}
/>
</SettingsSubsection>
</>
);
};

interface ManagementSectionProps {
onDeactivateClicked: () => void;
}

private onPasswordChangeError = (err: Error): void => {
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>
);
};

const GeneralUserSettingsTab: React.FC<IProps> = ({ closeSettingsFn }) => {
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 changePasswordCap = capabilities["m.change_password"];

// You can change your password so long as the capability isn't explicitly disabled. The implicit
// behaviour is you can change your password when the capability is missing or has not-false as
// the enabled flag value.
const canChangePassword = !changePasswordCap || changePasswordCap["enabled"] !== false;

await sdkContext.oidcClientStore.readyPromise; // wait for the store to be ready
const externalAccountManagementUrl = sdkContext.oidcClientStore.accountManagementEndpoint;
// 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
// 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 canSetDisplayName =
!capabilities["m.set_displayname"] || capabilities["m.set_displayname"].enabled === true;
const canSetAvatar = !capabilities["m.set_avatar_url"] || capabilities["m.set_avatar_url"].enabled === true;

setCanMake3pidChanges(canMake3pidChanges);
setCanSetDisplayName(canSetDisplayName);
setCanSetAvatar(canSetAvatar);
setExternalAccountManagementUrl(externalAccountManagementUrl);
setCanChangePassword(canChangePassword);
})();
}, [cli, sdkContext.oidcClientStore]);

const onPasswordChangeError = useCallback((err: Error): void => {
logger.error("Failed to change password: " + err);

let underlyingError = err;
Expand Down Expand Up @@ -127,85 +163,49 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
title: _t("settings|general|error_password_change_title"),
description: errorMessageToDisplay,
});
};
}, []);

private onPasswordChanged = (): void => {
const onPasswordChanged = useCallback((): void => {
const description = _t("settings|general|password_change_success");
// TODO: Figure out a design that doesn't involve replacing the current dialog
Modal.createDialog(ErrorDialog, {
title: _t("common|success"),
description,
});
};
}, []);

private onDeactivateClicked = (): void => {
const onDeactivateClicked = useCallback((): void => {
Modal.createDialog(DeactivateAccountDialog, {
onFinished: (success) => {
if (success) this.props.closeSettingsFn();
if (success) 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>
</>
);
}
}, [closeSettingsFn]);

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>
);
let accountManagementSection: JSX.Element | undefined;
const isAccountManagedExternally = Boolean(externalAccountManagementUrl);
if (SettingsStore.getValue(UIFeature.Deactivate) && !isAccountManagedExternally) {
accountManagementSection = <ManagementSection onDeactivateClicked={onDeactivateClicked} />;
}

public render(): React.ReactNode {
let accountManagementSection: JSX.Element | undefined;
const isAccountManagedExternally = !!this.state.externalAccountManagementUrl;
if (SettingsStore.getValue(UIFeature.Deactivate) && !isAccountManagedExternally) {
accountManagementSection = this.renderManagementSection();
}
return (
<SettingsTab data-testid="mx_GeneralUserSettingsTab">
<SettingsSection>
<UserProfileSettings
externalAccountManagementUrl={externalAccountManagementUrl}
canSetDisplayName={canSetDisplayName}
canSetAvatar={canSetAvatar}
/>
<UserPersonalInfoSettings canMake3pidChanges={canMake3pidChanges} />
<AccountSection
canChangePassword={canChangePassword}
onPasswordChanged={onPasswordChanged}
onPasswordChangeError={onPasswordChangeError}
/>
</SettingsSection>
{accountManagementSection}
</SettingsTab>
);
};

return (
<SettingsTab data-testid="mx_GeneralUserSettingsTab">
<SettingsSection>
<UserProfileSettings
externalAccountManagementUrl={this.state.externalAccountManagementUrl}
canSetDisplayName={this.state.canSetDisplayName}
canSetAvatar={this.state.canSetAvatar}
/>
<UserPersonalInfoSettings canMake3pidChanges={this.state.canMake3pidChanges} />
{this.renderAccountSection()}
</SettingsSection>
{accountManagementSection}
</SettingsTab>
);
}
}
export default GeneralUserSettingsTab;

0 comments on commit 9cd0c24

Please sign in to comment.