diff --git a/src/components/Buttons/CloseButton.tsx b/src/components/Buttons/CloseButton.tsx
new file mode 100644
index 0000000000..073d95552c
--- /dev/null
+++ b/src/components/Buttons/CloseButton.tsx
@@ -0,0 +1,25 @@
+import { Close } from "@mui/icons-material";
+import { IconButton } from "@mui/material";
+import { CSSProperties, ReactElement } from "react";
+
+interface CloseButtonProps {
+ close: () => void;
+}
+
+export default function CloseButton(props: CloseButtonProps): ReactElement {
+ const closeButtonStyle: CSSProperties = {
+ position: "absolute",
+ top: 0,
+ ...(document.body.dir === "rtl" ? { left: 0 } : { right: 0 }),
+ };
+
+ return (
+
+
+
+ );
+}
diff --git a/src/components/Buttons/DeleteButtonWithDialog.tsx b/src/components/Buttons/DeleteButtonWithDialog.tsx
new file mode 100644
index 0000000000..472e1c1bb4
--- /dev/null
+++ b/src/components/Buttons/DeleteButtonWithDialog.tsx
@@ -0,0 +1,45 @@
+import { Delete } from "@mui/icons-material";
+import { ReactElement, useState } from "react";
+
+import { IconButtonWithTooltip } from "components/Buttons";
+import { CancelConfirmDialog } from "components/Dialogs";
+
+interface DeleteButtonWithDialogProps {
+ buttonId: string;
+ buttonIdCancel?: string;
+ buttonIdConfirm?: string;
+ delete: () => void | Promise;
+ disabled?: boolean;
+ textId: string;
+ tooltipTextId?: string;
+}
+
+export default function DeleteButtonWithDialog(
+ props: DeleteButtonWithDialogProps
+): ReactElement {
+ const [open, setOpen] = useState(false);
+
+ const handleConfirm = async (): Promise => {
+ await props.delete();
+ setOpen(false);
+ };
+
+ return (
+ <>
+ }
+ onClick={props.disabled ? undefined : () => setOpen(true)}
+ textId={props.tooltipTextId || props.textId}
+ />
+ setOpen(false)}
+ handleConfirm={handleConfirm}
+ open={open}
+ textId={props.textId}
+ />
+ >
+ );
+}
diff --git a/src/components/Buttons/FlagButton.tsx b/src/components/Buttons/FlagButton.tsx
index 5dd801c6d1..941b13c544 100644
--- a/src/components/Buttons/FlagButton.tsx
+++ b/src/components/Buttons/FlagButton.tsx
@@ -52,7 +52,7 @@ export default function FlagButton(props: FlagButtonProps): ReactElement {
}
text={text}
textId={active ? "flags.edit" : "flags.add"}
- small
+ size="small"
onClick={
props.updateFlag ? () => setOpen(true) : active ? () => {} : undefined
}
diff --git a/src/components/Buttons/IconButtonWithTooltip.tsx b/src/components/Buttons/IconButtonWithTooltip.tsx
index b717e8f467..51527916db 100644
--- a/src/components/Buttons/IconButtonWithTooltip.tsx
+++ b/src/components/Buttons/IconButtonWithTooltip.tsx
@@ -1,13 +1,13 @@
import { Tooltip, IconButton } from "@mui/material";
-import { ReactElement, ReactNode } from "react";
+import { MouseEventHandler, ReactElement, ReactNode } from "react";
import { useTranslation } from "react-i18next";
interface IconButtonWithTooltipProps {
icon: ReactElement;
text?: ReactNode;
textId?: string;
- small?: boolean;
- onClick?: () => void;
+ size?: "large" | "medium" | "small";
+ onClick?: MouseEventHandler;
buttonId: string;
side?: "bottom" | "left" | "right" | "top";
}
@@ -25,7 +25,7 @@ export default function IconButtonWithTooltip(
diff --git a/src/components/Buttons/PartOfSpeechButton.tsx b/src/components/Buttons/PartOfSpeechButton.tsx
index 05db4aa1fb..b7eac606c9 100644
--- a/src/components/Buttons/PartOfSpeechButton.tsx
+++ b/src/components/Buttons/PartOfSpeechButton.tsx
@@ -38,7 +38,7 @@ export default function PartOfSpeech(props: PartOfSpeechProps): ReactElement {
icon={}
onClick={props.onClick}
side="top"
- small
+ size="small"
text={hoverText}
/>
);
diff --git a/src/components/Buttons/index.ts b/src/components/Buttons/index.ts
index 3889259e5f..4f50683ce9 100644
--- a/src/components/Buttons/index.ts
+++ b/src/components/Buttons/index.ts
@@ -1,3 +1,5 @@
+import CloseButton from "components/Buttons/CloseButton";
+import DeleteButtonWithDialog from "components/Buttons/DeleteButtonWithDialog";
import FileInputButton from "components/Buttons/FileInputButton";
import FlagButton from "components/Buttons/FlagButton";
import IconButtonWithTooltip from "components/Buttons/IconButtonWithTooltip";
@@ -7,6 +9,8 @@ import PartOfSpeechButton from "components/Buttons/PartOfSpeechButton";
import UndoButton from "components/Buttons/UndoButton";
export {
+ CloseButton,
+ DeleteButtonWithDialog,
FileInputButton,
FlagButton,
IconButtonWithTooltip,
diff --git a/src/components/Buttons/tests/DeleteButtonWithDialog.test.tsx b/src/components/Buttons/tests/DeleteButtonWithDialog.test.tsx
new file mode 100644
index 0000000000..07213d5706
--- /dev/null
+++ b/src/components/Buttons/tests/DeleteButtonWithDialog.test.tsx
@@ -0,0 +1,85 @@
+import { ReactTestRenderer, act, create } from "react-test-renderer";
+
+import "tests/reactI18nextMock";
+
+import DeleteButtonWithDialog from "components/Buttons/DeleteButtonWithDialog";
+import { CancelConfirmDialog } from "components/Dialogs";
+
+// Dialog uses portals, which are not supported in react-test-renderer.
+jest.mock("@mui/material", () => {
+ const materialUiCore = jest.requireActual("@mui/material");
+ return {
+ ...jest.requireActual("@mui/material"),
+ Dialog: materialUiCore.Container,
+ };
+});
+
+const mockDelete = jest.fn();
+const buttonId = "button-id";
+const buttonIdCancel = "button-id-cancel";
+const buttonIdConfirm = "button-id-confirm";
+const textId = "text-id";
+
+let cellHandle: ReactTestRenderer;
+
+const renderDeleteCell = async (): Promise => {
+ await act(async () => {
+ cellHandle = create(
+
+ );
+ });
+};
+
+beforeEach(async () => {
+ jest.clearAllMocks();
+ await renderDeleteCell();
+});
+
+describe("DeleteCell", () => {
+ it("has working dialog buttons", async () => {
+ const dialog = cellHandle.root.findByType(CancelConfirmDialog);
+ const deleteButton = cellHandle.root.findByProps({ id: buttonId });
+
+ expect(dialog.props.open).toBeFalsy();
+ await act(async () => {
+ deleteButton.props.onClick();
+ });
+ expect(dialog.props.open).toBeTruthy();
+ const cancelButton = cellHandle.root.findByProps({ id: buttonIdCancel });
+ await act(async () => {
+ cancelButton.props.onClick();
+ });
+ expect(dialog.props.open).toBeFalsy();
+ await act(async () => {
+ deleteButton.props.onClick();
+ });
+ expect(dialog.props.open).toBeTruthy();
+ const confButton = cellHandle.root.findByProps({ id: buttonIdConfirm });
+ await act(async () => {
+ await confButton.props.onClick();
+ });
+ expect(dialog.props.open).toBeFalsy();
+ });
+
+ it("only deletes after confirmation", async () => {
+ const deleteButton = cellHandle.root.findByProps({ id: buttonId });
+
+ await act(async () => {
+ deleteButton.props.onClick();
+ cellHandle.root.findByProps({ id: buttonIdCancel }).props.onClick();
+ deleteButton.props.onClick();
+ });
+ expect(mockDelete).not.toHaveBeenCalled();
+ const confButton = cellHandle.root.findByProps({ id: buttonIdConfirm });
+ await act(async () => {
+ await confButton.props.onClick();
+ });
+ expect(mockDelete).toHaveBeenCalled();
+ });
+});
diff --git a/src/components/DataEntry/DataEntryTable/NewEntry/SenseDialog.tsx b/src/components/DataEntry/DataEntryTable/NewEntry/SenseDialog.tsx
index dd800185ec..121cbff0f7 100644
--- a/src/components/DataEntry/DataEntryTable/NewEntry/SenseDialog.tsx
+++ b/src/components/DataEntry/DataEntryTable/NewEntry/SenseDialog.tsx
@@ -1,9 +1,7 @@
-import { Close } from "@mui/icons-material";
import {
Dialog,
DialogContent,
Grid,
- IconButton,
MenuList,
Typography,
} from "@mui/material";
@@ -11,6 +9,7 @@ import { ReactElement } from "react";
import { useTranslation } from "react-i18next";
import { GramCatGroup, Sense, Word } from "api/models";
+import { CloseButton } from "components/Buttons";
import StyledMenuItem from "components/DataEntry/DataEntryTable/NewEntry/StyledMenuItem";
import {
DomainCell,
@@ -107,12 +106,7 @@ export function SenseList(props: SenseListProps): ReactElement {
return (
<>
{/* Cancel button */}
- props.closeDialog()}
- style={{ position: "absolute", right: 0, top: 0 }}
- >
-
-
+ props.closeDialog()} />
{/* Header */}
{t("addWords.selectSense")}
{/* Sense options */}
diff --git a/src/components/DataEntry/DataEntryTable/NewEntry/VernDialog.tsx b/src/components/DataEntry/DataEntryTable/NewEntry/VernDialog.tsx
index 3baa246109..cfb5b89de0 100644
--- a/src/components/DataEntry/DataEntryTable/NewEntry/VernDialog.tsx
+++ b/src/components/DataEntry/DataEntryTable/NewEntry/VernDialog.tsx
@@ -1,9 +1,7 @@
-import { Close } from "@mui/icons-material";
import {
Dialog,
DialogContent,
Grid,
- IconButton,
MenuList,
Typography,
} from "@mui/material";
@@ -11,6 +9,7 @@ import { ReactElement } from "react";
import { useTranslation } from "react-i18next";
import { GramCatGroup, Word } from "api/models";
+import { CloseButton } from "components/Buttons";
import StyledMenuItem from "components/DataEntry/DataEntryTable/NewEntry/StyledMenuItem";
import {
DomainCell,
@@ -108,12 +107,7 @@ export function VernList(props: VernListProps): ReactElement {
return (
<>
{/* Cancel button */}
- props.closeDialog()}
- style={{ position: "absolute", right: 0, top: 0 }}
- >
-
-
+ props.closeDialog()} />
{/* Header */}
{t("addWords.selectEntry")}
{/* Entry options */}
diff --git a/src/components/Dialogs/DeleteEditTextDialog.tsx b/src/components/Dialogs/DeleteEditTextDialog.tsx
index afbc9c8a87..ab27fe933c 100644
--- a/src/components/Dialogs/DeleteEditTextDialog.tsx
+++ b/src/components/Dialogs/DeleteEditTextDialog.tsx
@@ -97,7 +97,7 @@ export default function DeleteEditTextDialog(
diff --git a/src/components/Dialogs/UploadImage.tsx b/src/components/Dialogs/UploadImage.tsx
new file mode 100644
index 0000000000..92c232f67f
--- /dev/null
+++ b/src/components/Dialogs/UploadImage.tsx
@@ -0,0 +1,77 @@
+import { Grid, Typography } from "@mui/material";
+import { FormEvent, ReactElement, useState } from "react";
+import { useTranslation } from "react-i18next";
+
+import { FileInputButton, LoadingDoneButton } from "components/Buttons";
+
+interface ImageUploadProps {
+ doneCallback?: () => void;
+ uploadImage: (imgFile: File) => Promise;
+}
+
+/**
+ * Allows the current user to select an image and upload it
+ */
+export default function ImageUpload(props: ImageUploadProps): ReactElement {
+ const [file, setFile] = useState();
+ const [filename, setFilename] = useState();
+ const [loading, setLoading] = useState(false);
+ const [done, setDone] = useState(false);
+ const { t } = useTranslation();
+
+ function updateFile(file: File): void {
+ if (file) {
+ setFile(file);
+ setFilename(file.name);
+ }
+ }
+
+ async function upload(e: FormEvent): Promise {
+ e.preventDefault();
+ e.stopPropagation();
+ if (file) {
+ setLoading(true);
+ await props
+ .uploadImage(file)
+ .then(onDone)
+ .catch(() => setLoading(false));
+ }
+ }
+
+ async function onDone(): Promise {
+ setDone(true);
+ if (props.doneCallback) {
+ setTimeout(props.doneCallback, 500);
+ }
+ }
+
+ return (
+
+ );
+}
diff --git a/src/components/Dialogs/UploadImageDialog.tsx b/src/components/Dialogs/UploadImageDialog.tsx
new file mode 100644
index 0000000000..226402b45d
--- /dev/null
+++ b/src/components/Dialogs/UploadImageDialog.tsx
@@ -0,0 +1,30 @@
+import { Dialog, DialogContent, DialogTitle } from "@mui/material";
+import { ReactElement } from "react";
+import { useTranslation } from "react-i18next";
+
+import UploadImage from "components/Dialogs/UploadImage";
+
+interface UploadImageDialogProps {
+ close: () => void;
+ open: boolean;
+ titleId: string;
+ uploadImage: (imageFile: File) => Promise;
+}
+
+export default function UploadImageDialog(
+ props: UploadImageDialogProps
+): ReactElement {
+ const { t } = useTranslation();
+
+ return (
+
+ );
+}
diff --git a/src/components/Dialogs/index.ts b/src/components/Dialogs/index.ts
index f501a59597..7913acbec1 100644
--- a/src/components/Dialogs/index.ts
+++ b/src/components/Dialogs/index.ts
@@ -2,10 +2,12 @@ import ButtonConfirmation from "components/Dialogs/ButtonConfirmation";
import CancelConfirmDialog from "components/Dialogs/CancelConfirmDialog";
import DeleteEditTextDialog from "components/Dialogs/DeleteEditTextDialog";
import EditTextDialog from "components/Dialogs/EditTextDialog";
+import UploadImageDialog from "components/Dialogs/UploadImageDialog";
export {
ButtonConfirmation,
CancelConfirmDialog,
DeleteEditTextDialog,
EditTextDialog,
+ UploadImageDialog,
};
diff --git a/src/components/ProjectSettings/ProjectLanguages.tsx b/src/components/ProjectSettings/ProjectLanguages.tsx
index 94466860b2..db6da1a401 100644
--- a/src/components/ProjectSettings/ProjectLanguages.tsx
+++ b/src/components/ProjectSettings/ProjectLanguages.tsx
@@ -115,14 +115,14 @@ export default function ProjectLanguages(
}
textId="projectSettings.language.makeDefaultAnalysisLanguage"
- small
+ size="small"
onClick={() => setNewAnalysisDefault(index)}
buttonId={`analysis-language-${index}-bump`}
/>
}
textId="projectSettings.language.deleteAnalysisLanguage"
- small
+ size="small"
onClick={() => deleteAnalysisWritingSystem(index)}
buttonId={`analysis-language-${index}-delete`}
/>
@@ -282,8 +282,8 @@ export default function ProjectLanguages(
) : (
}
- textId={"projectSettings.language.changeName"}
- small
+ size="small"
+ textId="projectSettings.language.changeName"
onClick={() => setChangeVernName(true)}
buttonId={editVernacularNameButtonId}
/>
diff --git a/src/components/Pronunciations/AudioPlayer.tsx b/src/components/Pronunciations/AudioPlayer.tsx
index a2a0dcbc99..7e52a549af 100644
--- a/src/components/Pronunciations/AudioPlayer.tsx
+++ b/src/components/Pronunciations/AudioPlayer.tsx
@@ -22,9 +22,10 @@ import { themeColors } from "types/theme";
interface PlayerProps {
deleteAudio: (fileName: string) => void;
fileName: string;
- isPlaying?: boolean;
onClick?: () => void;
pronunciationUrl: string;
+ size?: "large" | "medium" | "small";
+ warningTextId?: string;
}
const iconStyle: CSSProperties = { color: themeColors.success };
@@ -106,7 +107,7 @@ export default function AudioPlayer(props: PlayerProps): ReactElement {
onTouchEnd={enableContextMenu}
aria-label="play"
id={`audio-${props.fileName}`}
- size="large"
+ size={props.size || "large"}
>
{isPlaying ? : }
@@ -141,7 +142,7 @@ export default function AudioPlayer(props: PlayerProps): ReactElement {
setDeleteConf(false)}
onConfirm={() => props.deleteAudio(props.fileName)}
diff --git a/src/components/UserSettings/ClickableAvatar.tsx b/src/components/UserSettings/ClickableAvatar.tsx
index 62939421e4..6ba5ae9805 100644
--- a/src/components/UserSettings/ClickableAvatar.tsx
+++ b/src/components/UserSettings/ClickableAvatar.tsx
@@ -1,9 +1,10 @@
import { CameraAlt, Person } from "@mui/icons-material";
-import { Avatar, Dialog, DialogContent, DialogTitle } from "@mui/material";
+import { Avatar } from "@mui/material";
import { ReactElement, useState } from "react";
-import { getAvatar } from "backend/localStorage";
-import AvatarUpload from "components/UserSettings/AvatarUpload";
+import { uploadAvatar } from "backend";
+import { getAvatar, getUserId } from "backend/localStorage";
+import { UploadImageDialog } from "components/Dialogs";
const avatarStyle = { height: 60, width: 60 };
const avatarOverlayStyle = {
@@ -48,12 +49,12 @@ export default function ClickableAvatar(
-
+ uploadAvatar(getUserId(), imgFile)}
+ />
>
);
}
diff --git a/src/components/UserSettings/tests/AvatarUpload.test.tsx b/src/components/UserSettings/tests/AvatarUpload.test.tsx
deleted file mode 100644
index 5bf8f4c4f9..0000000000
--- a/src/components/UserSettings/tests/AvatarUpload.test.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import renderer from "react-test-renderer";
-
-import "tests/reactI18nextMock";
-
-import AvatarUpload from "components/UserSettings/AvatarUpload";
-
-let testRenderer: renderer.ReactTestRenderer;
-
-describe("AvatarUpload", () => {
- it("renders", () => {
- renderer.act(() => {
- testRenderer = renderer.create();
- });
- expect(testRenderer.root.findAllByType(AvatarUpload)).toHaveLength(1);
- });
-});
diff --git a/src/goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/DropWord.tsx b/src/goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/DropWord.tsx
index 07aeddae21..ece2875cdf 100644
--- a/src/goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/DropWord.tsx
+++ b/src/goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/DropWord.tsx
@@ -90,9 +90,9 @@ export default function DropWord(props: DropWordProps): ReactElement {
{protectedWithOneChild && (
}
- textId={"mergeDups.helpText.protectedWord"}
- side={"top"}
- small
+ side="top"
+ size="small"
+ textId="mergeDups.helpText.protectedWord"
buttonId={`word-${props.wordId}-protected`}
/>
)}
diff --git a/src/goals/MergeDuplicates/MergeDupsStep/SenseCardContent.tsx b/src/goals/MergeDuplicates/MergeDupsStep/SenseCardContent.tsx
index 5bf24d91b6..6b5d01c05d 100644
--- a/src/goals/MergeDuplicates/MergeDupsStep/SenseCardContent.tsx
+++ b/src/goals/MergeDuplicates/MergeDupsStep/SenseCardContent.tsx
@@ -50,9 +50,9 @@ export default function SenseCardContent(
{protectedWarning && (
}
- textId={"mergeDups.helpText.protectedSense"}
- side={"top"}
- small
+ side="top"
+ size="small"
+ textId="mergeDups.helpText.protectedSense"
buttonId={`sense-${props.senses[0].guid}-protected`}
/>
)}
diff --git a/src/goals/ReviewEntries/ReviewEntriesTable/CellComponents/DeleteCell.tsx b/src/goals/ReviewEntries/ReviewEntriesTable/CellComponents/DeleteCell.tsx
index dce5f70664..de7c0a42bc 100644
--- a/src/goals/ReviewEntries/ReviewEntriesTable/CellComponents/DeleteCell.tsx
+++ b/src/goals/ReviewEntries/ReviewEntriesTable/CellComponents/DeleteCell.tsx
@@ -1,26 +1,21 @@
-import { Delete } from "@mui/icons-material";
-import { IconButton, Tooltip } from "@mui/material";
-import { ReactElement, useState } from "react";
-import { useTranslation } from "react-i18next";
+import { ReactElement } from "react";
import { deleteFrontierWord as deleteFromBackend } from "backend";
-import { CancelConfirmDialog } from "components/Dialogs";
+import { DeleteButtonWithDialog } from "components/Buttons";
import { deleteWord } from "goals/ReviewEntries/Redux/ReviewEntriesActions";
import { ReviewEntriesWord } from "goals/ReviewEntries/ReviewEntriesTypes";
import { useAppDispatch } from "types/hooks";
-export const buttonId = (wordId: string): string => `row-${wordId}-delete`;
-export const buttonIdCancel = "delete-cancel";
-export const buttonIdConfirm = "delete-confirm";
+const buttonId = (wordId: string): string => `row-${wordId}-delete`;
+const buttonIdCancel = "delete-cancel";
+const buttonIdConfirm = "delete-confirm";
interface DeleteCellProps {
rowData: ReviewEntriesWord;
}
export default function DeleteCell(props: DeleteCellProps): ReactElement {
- const [dialogOpen, setDialogOpen] = useState(false);
const dispatch = useAppDispatch();
- const { t } = useTranslation();
const word = props.rowData;
const disabled = word.protected || !!word.senses.find((s) => s.protected);
@@ -28,41 +23,17 @@ export default function DeleteCell(props: DeleteCellProps): ReactElement {
async function deleteFrontierWord(): Promise {
await deleteFromBackend(word.id);
dispatch(deleteWord(word.id));
- handleClose();
- }
-
- function handleOpen(): void {
- setDialogOpen(true);
- }
- function handleClose(): void {
- setDialogOpen(false);
}
return (
- <>
-
-
-
-
-
-
-
-
- >
+
);
}
diff --git a/src/goals/ReviewEntries/ReviewEntriesTable/CellComponents/SenseCell.tsx b/src/goals/ReviewEntries/ReviewEntriesTable/CellComponents/SenseCell.tsx
index b3b9fe5f24..b823fd07e2 100644
--- a/src/goals/ReviewEntries/ReviewEntriesTable/CellComponents/SenseCell.tsx
+++ b/src/goals/ReviewEntries/ReviewEntriesTable/CellComponents/SenseCell.tsx
@@ -1,8 +1,8 @@
import { Add, Delete, RestoreFromTrash } from "@mui/icons-material";
-import { Chip, IconButton, Tooltip } from "@mui/material";
+import { Chip } from "@mui/material";
import { ReactElement } from "react";
-import { useTranslation } from "react-i18next";
+import { IconButtonWithTooltip } from "components/Buttons";
import { FieldParameterStandard } from "goals/ReviewEntries/ReviewEntriesTable/CellColumns";
import AlignedList from "goals/ReviewEntries/ReviewEntriesTable/CellComponents/AlignedList";
import { ReviewEntriesSense } from "goals/ReviewEntries/ReviewEntriesTypes";
@@ -12,8 +12,6 @@ interface SenseCellProps extends FieldParameterStandard {
}
export default function SenseCell(props: SenseCellProps): ReactElement {
- const { t } = useTranslation();
-
function addSense(): ReactElement {
const senses = [...props.rowData.senses, new ReviewEntriesSense()];
return (
@@ -32,22 +30,16 @@ export default function SenseCell(props: SenseCellProps): ReactElement {
(
- : }
key={sense.guid}
- >
-
- props.delete!(sense.guid)}
- id={`sense-${sense.guid}-delete`}
- disabled={sense.protected}
- >
- {sense.deleted ? : }
-
-
-
+ onClick={
+ sense.protected ? undefined : () => props.delete!(sense.guid)
+ }
+ size="small"
+ textId={sense.protected ? "reviewEntries.deleteDisabled" : undefined}
+ />
))}
bottomCell={addSense()}
/>
diff --git a/src/goals/ReviewEntries/ReviewEntriesTable/CellComponents/tests/DeleteCell.test.tsx b/src/goals/ReviewEntries/ReviewEntriesTable/CellComponents/tests/DeleteCell.test.tsx
index ad471603da..80fd1e707b 100644
--- a/src/goals/ReviewEntries/ReviewEntriesTable/CellComponents/tests/DeleteCell.test.tsx
+++ b/src/goals/ReviewEntries/ReviewEntriesTable/CellComponents/tests/DeleteCell.test.tsx
@@ -4,13 +4,9 @@ import configureMockStore from "redux-mock-store";
import "tests/reactI18nextMock";
-import { CancelConfirmDialog } from "components/Dialogs";
+import { DeleteButtonWithDialog } from "components/Buttons";
import { defaultState as reviewEntriesState } from "goals/ReviewEntries/Redux/ReviewEntriesReduxTypes";
-import DeleteCell, {
- buttonId,
- buttonIdCancel,
- buttonIdConfirm,
-} from "goals/ReviewEntries/ReviewEntriesTable/CellComponents/DeleteCell";
+import DeleteCell from "goals/ReviewEntries/ReviewEntriesTable/CellComponents/DeleteCell";
import mockWords from "goals/ReviewEntries/tests/WordsMock";
// Dialog uses portals, which are not supported in react-test-renderer.
@@ -23,7 +19,7 @@ jest.mock("@mui/material", () => {
});
jest.mock("backend", () => ({
- deleteFrontierWord: () => mockDeleteFrontierWord(),
+ deleteFrontierWord: () => jest.fn(),
}));
jest.mock("types/hooks", () => {
return {
@@ -35,11 +31,8 @@ jest.mock("types/hooks", () => {
};
});
-const mockDeleteFrontierWord = jest.fn();
-
const mockStore = configureMockStore()({ reviewEntriesState });
const mockWord = mockWords()[0];
-const buttonIdDelete = buttonId(mockWord.id);
let cellHandle: ReactTestRenderer;
@@ -59,45 +52,7 @@ beforeEach(async () => {
});
describe("DeleteCell", () => {
- it("has working dialog buttons", async () => {
- const dialog = cellHandle.root.findByType(CancelConfirmDialog);
- const deleteButton = cellHandle.root.findByProps({ id: buttonIdDelete });
- const cancelButton = cellHandle.root.findByProps({ id: buttonIdCancel });
- const confButton = cellHandle.root.findByProps({ id: buttonIdConfirm });
-
- expect(dialog.props.open).toBeFalsy();
- await act(async () => {
- deleteButton.props.onClick();
- });
- expect(dialog.props.open).toBeTruthy();
- await act(async () => {
- cancelButton.props.onClick();
- });
- expect(dialog.props.open).toBeFalsy();
- await act(async () => {
- deleteButton.props.onClick();
- });
- expect(dialog.props.open).toBeTruthy();
- await act(async () => {
- await confButton.props.onClick();
- });
- expect(dialog.props.open).toBeFalsy();
- });
-
- it("only deletes after confirmation", async () => {
- const deleteButton = cellHandle.root.findByProps({ id: buttonIdDelete });
- const cancelButton = cellHandle.root.findByProps({ id: buttonIdCancel });
- const confButton = cellHandle.root.findByProps({ id: buttonIdConfirm });
-
- await act(async () => {
- deleteButton.props.onClick();
- cancelButton.props.onClick();
- deleteButton.props.onClick();
- });
- expect(mockDeleteFrontierWord).not.toBeCalled();
- await act(async () => {
- await confButton.props.onClick();
- });
- expect(mockDeleteFrontierWord).toBeCalled();
+ it("renders", () => {
+ cellHandle.root.findByType(DeleteButtonWithDialog);
});
});