Skip to content

Commit

Permalink
Create a common undo button
Browse files Browse the repository at this point in the history
  • Loading branch information
imnasnainaec committed Oct 25, 2023
1 parent b720d2e commit e28e452
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 128 deletions.
61 changes: 61 additions & 0 deletions src/components/Buttons/UndoButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Button, Grid } from "@mui/material";
import { ReactElement, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";

import { CancelConfirmDialog } from "components/Dialogs";

interface UndoButtonProps {
buttonIdEnabled?: string;
buttonIdCancel?: string;
buttonIdConfirm?: string;
textIdDialog: string;
textIdDisabled: string;
textIdEnabled: string;
isUndoAllowed: () => Promise<boolean>;
undo: () => Promise<void>;
}

export default function UndoButton(props: UndoButtonProps): ReactElement {
const isUndoAllowed = props.isUndoAllowed;

const [isUndoEnabled, setUndoEnabled] = useState(false);
const [undoDialogOpen, setUndoDialogOpen] = useState(false);

const { t } = useTranslation();

useEffect(() => {
if (!undoDialogOpen) {
isUndoAllowed().then(setUndoEnabled);
}
}, [isUndoAllowed, undoDialogOpen]);

return (
<Grid container direction="column" justifyContent="center">
{isUndoEnabled ? (
<div>
<Button
variant="outlined"
id={props.buttonIdEnabled}
onClick={() => setUndoDialogOpen(true)}
>
{t(props.textIdEnabled)}
</Button>
<CancelConfirmDialog
open={undoDialogOpen}
textId={props.textIdDialog}
handleCancel={() => setUndoDialogOpen(false)}
handleConfirm={() =>
props.undo().then(() => setUndoDialogOpen(false))
}
buttonIdCancel={props.buttonIdCancel}
buttonIdConfirm={props.buttonIdConfirm}
/>
</div>
) : (
<div>
<Button disabled>{t(props.textIdDisabled)}</Button>
</div>
)}
</Grid>
);
}
2 changes: 2 additions & 0 deletions src/components/Buttons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import IconButtonWithTooltip from "components/Buttons/IconButtonWithTooltip";
import LoadingButton from "components/Buttons/LoadingButton";
import LoadingDoneButton from "components/Buttons/LoadingDoneButton";
import PartOfSpeechButton from "components/Buttons/PartOfSpeechButton";
import UndoButton from "components/Buttons/UndoButton";

export {
FileInputButton,
Expand All @@ -12,4 +13,5 @@ export {
LoadingButton,
LoadingDoneButton,
PartOfSpeechButton,
UndoButton,
};
79 changes: 15 additions & 64 deletions src/goals/MergeDuplicates/MergeDupsCompleted.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { ArrowRightAlt } from "@mui/icons-material";
import { Button, Card, Grid, Paper, Typography } from "@mui/material";
import { Card, Grid, Paper, Typography } from "@mui/material";
import { ReactElement, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";

import { Flag, MergeUndoIds, Sense, Word } from "api/models";
import { getFrontierWords, getWord, undoMerge } from "backend";
import { FlagButton } from "components/Buttons";
import { CancelConfirmDialog } from "components/Dialogs";
import { FlagButton, UndoButton } from "components/Buttons";
import SenseCardContent from "goals/MergeDuplicates/MergeDupsStep/SenseCardContent";
import { MergesCompleted } from "goals/MergeDuplicates/MergeDupsTypes";
import { StoreState } from "types";
Expand Down Expand Up @@ -45,6 +44,9 @@ export function MergesCount(changes: MergesCompleted): ReactElement {
}

function MergeChange(change: MergeUndoIds): ReactElement {
const handleIsUndoAllowed = (): Promise<boolean> =>
getFrontierWords().then((words) => doWordsIncludeMerges(words, change));

return (
<div key={change.parentIds[0] ?? "deleteOnly"}>
<Grid
Expand Down Expand Up @@ -74,73 +76,22 @@ function MergeChange(change: MergeUndoIds): ReactElement {
<WordPaper key={"deleteOnly"} wordId={""} />
)}
<UndoButton
merge={change}
textId="mergeDups.undo.undo"
dialogId="mergeDups.undo.undoDialog"
disabledId="mergeDups.undo.undoDisabled"
buttonIdEnabled={`merge-undo-${change.parentIds.join("-")}`}
buttonIdCancel="merge-undo-cancel"
buttonIdConfirm="merge-undo-confirm"
textIdDialog="mergeDups.undo.undoDialog"
textIdDisabled="mergeDups.undo.undoDisabled"
textIdEnabled="mergeDups.undo.undo"
isUndoAllowed={handleIsUndoAllowed}
undo={async () => {
await undoMerge(change);
}}
/>
</Grid>
</div>
);
}

interface UndoButtonProps {
merge: MergeUndoIds;
textId: string;
dialogId: string;
disabledId: string;
}

function UndoButton(props: UndoButtonProps): ReactElement {
const [isUndoBtnEnabled, setUndoBtnEnabled] = useState<boolean>(false);
const [undoDialogOpen, setUndoDialogOpen] = useState<boolean>(false);
const { t } = useTranslation();

useEffect(() => {
function checkFrontier(): void {
getFrontierWords().then((words) =>
setUndoBtnEnabled(
props.merge ? doWordsIncludeMerges(words, props.merge) : false
)
);
}
checkFrontier();
});

if (isUndoBtnEnabled) {
return (
<Grid container direction="column" justifyContent="center">
<div>
<Button
variant="outlined"
id={`merge-undo-${props.merge.parentIds.join("-")}`}
onClick={() => setUndoDialogOpen(true)}
>
{t(props.textId)}
</Button>
<CancelConfirmDialog
open={undoDialogOpen}
textId={props.dialogId}
handleCancel={() => setUndoDialogOpen(false)}
handleConfirm={() =>
undoMerge(props.merge).then(() => setUndoDialogOpen(false))
}
buttonIdCancel="merge-undo-cancel"
buttonIdConfirm="merge-undo-confirm"
/>
</div>
</Grid>
);
}
return (
<Grid container direction="column" justifyContent="center">
<div>
<Button disabled>{t(props.disabledId)}</Button>
</div>
</Grid>
);
}

export function doWordsIncludeMerges(
words: Word[],
merge: MergeUndoIds
Expand Down
85 changes: 21 additions & 64 deletions src/goals/ReviewEntries/ReviewEntriesCompleted.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ArrowRightAlt } from "@mui/icons-material";
import { Button, Grid, Typography } from "@mui/material";
import { ReactElement, useEffect, useState } from "react";
import { Grid, Typography } from "@mui/material";
import { ReactElement } from "react";
import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";

import { getFrontierWords, getWord, updateWord } from "backend";
import { CancelConfirmDialog } from "components/Dialogs";
import { UndoButton } from "components/Buttons";
import {
EntriesEdited,
EntryEdit,
Expand Down Expand Up @@ -41,7 +41,17 @@ export function EditsCount(changes: EntriesEdited): ReactElement {
);
}

async function undoEdit(edit: EntryEdit): Promise<void> {
const oldWord = await getWord(edit.oldId);
await updateWord({ ...oldWord, id: edit.newId });
}

function EditedEntry(props: { edit: EntryEdit }): ReactElement {
const handleIsUndoAllowed = (): Promise<boolean> =>
getFrontierWords().then(
(words) => words.findIndex((w) => w.id === props.edit.newId) !== -1
);

return (
<Grid container style={{ flexWrap: "nowrap", overflow: "auto" }}>
<Typography>{props.edit.oldId}</Typography>
Expand All @@ -58,68 +68,15 @@ function EditedEntry(props: { edit: EntryEdit }): ReactElement {
</Grid>
<Typography>{props.edit.newId}</Typography>
<UndoButton
edit={props.edit}
textId="reviewEntries.undo.undo"
dialogId="reviewEntries.undo.undoDialog"
disabledId="reviewEntries.undo.undoDisabled"
buttonIdEnabled={`edit-undo-${props.edit.newId}`}
buttonIdCancel="edit-undo-cancel"
buttonIdConfirm="edit-undo-confirm"
textIdDialog="reviewEntries.undo.undoDialog"
textIdDisabled="reviewEntries.undo.undoDisabled"
textIdEnabled="reviewEntries.undo.undo"
isUndoAllowed={handleIsUndoAllowed}
undo={() => undoEdit(props.edit)}
/>
</Grid>
);
}

interface UndoButtonProps {
edit: EntryEdit;
textId: string;
dialogId: string;
disabledId: string;
}

function UndoButton(props: UndoButtonProps): ReactElement {
const [isUndoEnabled, setUndoEnabled] = useState<boolean>(false);
const [undoDialogOpen, setUndoDialogOpen] = useState<boolean>(false);
const { t } = useTranslation();

useEffect(() => {
function checkFrontier(): void {
getFrontierWords().then((words) =>
setUndoEnabled(words.findIndex((w) => w.id === props.edit.newId) !== -1)
);
}
checkFrontier();
});

return isUndoEnabled ? (
<Grid container direction="column" justifyContent="center">
<div>
<Button
variant="outlined"
id={`edit-undo-${props.edit.newId}`}
onClick={() => setUndoDialogOpen(true)}
>
{t(props.textId)}
</Button>
<CancelConfirmDialog
open={undoDialogOpen}
textId={props.dialogId}
handleCancel={() => setUndoDialogOpen(false)}
handleConfirm={() =>
undoEdit(props.edit).then(() => setUndoDialogOpen(false))
}
buttonIdCancel="edit-undo-cancel"
buttonIdConfirm="edit-undo-confirm"
/>
</div>
</Grid>
) : (
<Grid container direction="column" justifyContent="center">
<div>
<Button disabled>{t(props.disabledId)}</Button>
</div>
</Grid>
);
}

const undoEdit = async (edit: EntryEdit): Promise<void> => {
const oldWord = await getWord(edit.oldId);
await updateWord({ ...oldWord, id: edit.newId });
};

0 comments on commit e28e452

Please sign in to comment.