diff --git a/src/components/views/dialogs/AskInviteAnywayDialog.tsx b/src/components/views/dialogs/AskInviteAnywayDialog.tsx index 9b9982618a..a35971992e 100644 --- a/src/components/views/dialogs/AskInviteAnywayDialog.tsx +++ b/src/components/views/dialogs/AskInviteAnywayDialog.tsx @@ -1,5 +1,6 @@ /* Copyright 2019 New Vector Ltd +Copyright 2023 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,14 +15,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from "react"; +import React, { useCallback } from "react"; import { _t } from "../../../languageHandler"; import SettingsStore from "../../../settings/SettingsStore"; import { SettingLevel } from "../../../settings/SettingLevel"; import BaseDialog from "./BaseDialog"; -interface IProps { +export interface AskInviteAnywayDialogProps { unknownProfileUsers: Array<{ userId: string; errorText: string; @@ -31,57 +32,58 @@ interface IProps { onFinished: (success: boolean) => void; } -export default class AskInviteAnywayDialog extends React.Component { - private onInviteClicked = (): void => { - this.props.onInviteAnyways(); - this.props.onFinished(true); - }; +export default function AskInviteAnywayDialog({ + onFinished, + onGiveUp, + onInviteAnyways, + unknownProfileUsers, +}: AskInviteAnywayDialogProps): JSX.Element { + const onInviteClicked = useCallback((): void => { + onInviteAnyways(); + onFinished(true); + }, [onInviteAnyways, onFinished]); - private onInviteNeverWarnClicked = (): void => { + const onInviteNeverWarnClicked = useCallback((): void => { SettingsStore.setValue("promptBeforeInviteUnknownUsers", null, SettingLevel.ACCOUNT, false); - this.props.onInviteAnyways(); - this.props.onFinished(true); - }; + onInviteAnyways(); + onFinished(true); + }, [onInviteAnyways, onFinished]); - private onGiveUpClicked = (): void => { - this.props.onGiveUp(); - this.props.onFinished(false); - }; + const onGiveUpClicked = useCallback((): void => { + onGiveUp(); + onFinished(false); + }, [onGiveUp, onFinished]); - public render(): React.ReactNode { - const errorList = this.props.unknownProfileUsers.map((address) => ( -
  • - {address.userId}: {address.errorText} -
  • - )); + const errorList = unknownProfileUsers.map((address) => ( +
  • + {address.userId}: {address.errorText} +
  • + )); - return ( - -
    -

    - {_t( - "Unable to find profiles for the Matrix IDs listed below - " + - "would you like to invite them anyway?", - )} -

    -
      {errorList}
    -
    + return ( + +
    +

    + {_t( + "Unable to find profiles for the Matrix IDs listed below - " + + "would you like to invite them anyway?", + )} +

    +
      {errorList}
    +
    -
    - - - -
    -
    - ); - } +
    + + + +
    +
    + ); } diff --git a/test/components/views/dialogs/AskInviteAnywayDialog-test.tsx b/test/components/views/dialogs/AskInviteAnywayDialog-test.tsx new file mode 100644 index 0000000000..9ff4c315da --- /dev/null +++ b/test/components/views/dialogs/AskInviteAnywayDialog-test.tsx @@ -0,0 +1,93 @@ +/* +Copyright 2023 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { getByText, render, RenderResult } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import React from "react"; + +import AskInviteAnywayDialog, { + AskInviteAnywayDialogProps, +} from "../../../../src/components/views/dialogs/AskInviteAnywayDialog"; +import SettingsStore from "../../../../src/settings/SettingsStore"; + +describe("AskInviteaAnywayDialog", () => { + const onFinished: jest.Mock = jest.fn(); + const onGiveUp: jest.Mock = jest.fn(); + const onInviteAnyways: jest.Mock = jest.fn(); + + function renderComponent(props: Partial = {}): RenderResult { + return render( + , + ); + } + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it("remembers to not warn again", async () => { + const { container } = renderComponent(); + + jest.spyOn(SettingsStore, "setValue").mockImplementation(async (): Promise => {}); + + const neverWarnAgainBtn = getByText(container, /never warn/); + await userEvent.click(neverWarnAgainBtn); + + expect(SettingsStore.setValue).toHaveBeenCalledWith( + "promptBeforeInviteUnknownUsers", + null, + expect.any(String), + false, + ); + expect(onInviteAnyways).toHaveBeenCalledTimes(1); + expect(onFinished).toHaveBeenCalledWith(true); + }); + + it("invites anyway", async () => { + const { container } = renderComponent(); + + jest.spyOn(SettingsStore, "setValue"); + + const inviteAnywayBtn = getByText(container, "Invite anyway"); + await userEvent.click(inviteAnywayBtn); + + expect(onInviteAnyways).toHaveBeenCalledTimes(1); + expect(onFinished).toHaveBeenCalledWith(true); + }); + + it("gives up", async () => { + const { container } = renderComponent(); + + jest.spyOn(SettingsStore, "setValue"); + + const closeBtn = getByText(container, /Close/); + await userEvent.click(closeBtn); + + expect(onGiveUp).toHaveBeenCalledTimes(1); + expect(onFinished).toHaveBeenCalledWith(false); + }); +});