diff --git a/src/components/Buttons/UndoButton.tsx b/src/components/Buttons/UndoButton.tsx index 72d3d79543..ada25bb818 100644 --- a/src/components/Buttons/UndoButton.tsx +++ b/src/components/Buttons/UndoButton.tsx @@ -1,4 +1,4 @@ -import { Button, Grid } from "@mui/material"; +import { Button } from "@mui/material"; import { ReactElement, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; @@ -30,35 +30,27 @@ export default function UndoButton(props: UndoButtonProps): ReactElement { } }, [isUndoAllowed, undoDialogOpen]); - return ( - - {isUndoEnabled ? ( -
- - setUndoDialogOpen(false)} - handleConfirm={() => - props.undo().then(() => setUndoDialogOpen(false)) - } - buttonIdCancel={props.buttonIdCancel} - buttonIdConfirm={props.buttonIdConfirm} - /> -
- ) : ( -
- -
- )} -
+ return isUndoEnabled ? ( + <> + + setUndoDialogOpen(false)} + handleConfirm={() => props.undo().then(() => setUndoDialogOpen(false))} + buttonIdCancel={props.buttonIdCancel} + buttonIdConfirm={props.buttonIdConfirm} + /> + + ) : ( + ); } diff --git a/src/components/WordCard/DomainChipsGrid.tsx b/src/components/WordCard/DomainChipsGrid.tsx index 19a994e139..3b8b714cd8 100644 --- a/src/components/WordCard/DomainChipsGrid.tsx +++ b/src/components/WordCard/DomainChipsGrid.tsx @@ -1,4 +1,4 @@ -import { Grid } from "@mui/material"; +import { Grid2 } from "@mui/material"; import { type ReactElement } from "react"; import { type SemanticDomain } from "api/models"; @@ -26,12 +26,14 @@ export default function DomainChipsGrid( }; return ( - + {props.semDoms.map((d) => ( - - - + ))} - + ); } diff --git a/src/components/WordCard/SenseCard.tsx b/src/components/WordCard/SenseCard.tsx index 4841f5b9ff..3cc1d43591 100644 --- a/src/components/WordCard/SenseCard.tsx +++ b/src/components/WordCard/SenseCard.tsx @@ -28,12 +28,7 @@ export default function SenseCard(props: SenseCardProps): ReactElement { const semDoms = props.sense.semanticDomains; return ( - + {/* Part of speech (if any) */}
diff --git a/src/components/WordCard/SummarySenseCard.tsx b/src/components/WordCard/SummarySenseCard.tsx index d07dee9f36..54d8702c71 100644 --- a/src/components/WordCard/SummarySenseCard.tsx +++ b/src/components/WordCard/SummarySenseCard.tsx @@ -1,4 +1,4 @@ -import { Card, CardContent, Chip, Grid, Typography } from "@mui/material"; +import { Card, CardContent, Chip, Grid2, Typography } from "@mui/material"; import { ReactElement } from "react"; import { useTranslation } from "react-i18next"; @@ -57,13 +57,11 @@ export default function SummarySenseCard( /> {/* Semantic domain numbers */} - + {domIds.map((id) => ( - - - + ))} - + ); diff --git a/src/components/WordCard/index.tsx b/src/components/WordCard/index.tsx index a91016cccd..e4a974cc30 100644 --- a/src/components/WordCard/index.tsx +++ b/src/components/WordCard/index.tsx @@ -5,6 +5,7 @@ import { CardContent, CardHeader, IconButton, + Stack, Typography, } from "@mui/material"; import { Fragment, ReactElement, useEffect, useState } from "react"; @@ -130,14 +131,16 @@ export default function WordCard(props: WordCardProps): ReactElement { {/* Senses */} {full ? ( - senses.map((s) => ( - - )) + + {senses.map((s) => ( + + ))} + ) : ( )} diff --git a/src/goals/CharacterInventory/CharInv/CharacterDetail/index.tsx b/src/goals/CharacterInventory/CharInv/CharacterDetail/index.tsx index 8580c3b240..c66b3541bc 100644 --- a/src/goals/CharacterInventory/CharInv/CharacterDetail/index.tsx +++ b/src/goals/CharacterInventory/CharInv/CharacterDetail/index.tsx @@ -1,5 +1,5 @@ import { Close } from "@mui/icons-material"; -import { Grid, IconButton, Typography } from "@mui/material"; +import { Grid2, IconButton, Typography } from "@mui/material"; import { ReactElement } from "react"; import CharacterInfo from "goals/CharacterInventory/CharInv/CharacterDetail/CharacterInfo"; @@ -18,7 +18,7 @@ export default function CharacterDetail( props: CharacterDetailProps ): ReactElement { return ( - - + {props.character} {""} {/* There is a zero-width joiner here in case of non-printing characters. */} - - + + - - + + props.close()} size="large"> {" "} - - + + - - + + - - + + - - + + ); } diff --git a/src/goals/CharacterInventory/CharInv/CharacterEntry.tsx b/src/goals/CharacterInventory/CharInv/CharacterEntry.tsx index d342dd16a2..3e828ff944 100644 --- a/src/goals/CharacterInventory/CharInv/CharacterEntry.tsx +++ b/src/goals/CharacterInventory/CharInv/CharacterEntry.tsx @@ -1,17 +1,39 @@ import { KeyboardArrowDown } from "@mui/icons-material"; -import { Button, Collapse, Grid } from "@mui/material"; +import { + Button, + Collapse, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, + Grid2, +} from "@mui/material"; import { ReactElement, ReactNode, useState } from "react"; import { useTranslation } from "react-i18next"; +import { LoadingButton } from "components/Buttons"; import { + exit, setRejectedCharacters, setValidCharacters, + uploadInventory, } from "goals/CharacterInventory/Redux/CharacterInventoryActions"; import { useAppDispatch, useAppSelector } from "rootRedux/hooks"; import { type StoreState } from "rootRedux/types"; import theme from "types/theme"; import { TextFieldWithFont } from "utilities/fontComponents"; +export enum CharInvCancelSaveIds { + ButtonCancel = "char-inv-cancel-button", + ButtonSave = "char-inv-save-button", + DialogCancel = "char-inv-cancel-dialog", + DialogCancelButtonNo = "char-inv-cancel-dialog-no-button", + DialogCancelButtonYes = "char-inv-cancel-dialog-yes-button", + DialogCancelText = "char-inv-cancel-dialog-text", + DialogCancelTitle = "char-inv-cancel-dialog-title", +} + /** * Allows for viewing and entering accepted and rejected characters in a * character set @@ -23,56 +45,89 @@ export default function CharacterEntry(): ReactElement { (state: StoreState) => state.characterInventoryState ); - const [checked, setChecked] = useState(false); + const [advancedOpen, setAdvancedOpen] = useState(false); + const [cancelDialogOpen, setCancelDialogOpen] = useState(false); + const [saveInProgress, setSaveInProgress] = useState(false); const { t } = useTranslation(); + const save = async (): Promise => { + setSaveInProgress(true); + await dispatch(uploadInventory()); + }; + return ( - - - + + {/* Cancel yes/no dialog */} + setCancelDialogOpen(false)} + open={cancelDialogOpen} /> - - - {/* Input for accepted characters */} - - dispatch(setValidCharacters(chars))} - /> - - - {/* Input for rejected characters */} - - dispatch(setRejectedCharacters(chars))} + + + {/* Advanced toggle-button */} + + + + + {/* Input for accepted characters */} + dispatch(setValidCharacters(chars))} + /> + + {/* Input for rejected characters */} + dispatch(setRejectedCharacters(chars))} + /> + +
); } @@ -95,10 +150,59 @@ function CharactersInput(props: CharactersInputProps): ReactElement { onChange={(e) => props.setCharacters(e.target.value.replace(/\s/g, "").split("")) } - style={{ maxWidth: 512, marginTop: theme.spacing(1) }} + style={{ marginTop: theme.spacing(2) }} value={props.characters.join("")} variant="outlined" vernacular /> ); } + +interface CancelDialogProps { + open: boolean; + onClose: () => void; +} + +/** "Are you sure?" dialog for the cancel button */ +function CancelDialog(props: CancelDialogProps): ReactElement { + const { t } = useTranslation(); + + return ( + props.onClose()} + open={props.open} + > + + {t("charInventory.dialog.title")} + + + + + {t("charInventory.dialog.content")} + + + + + + + + + + ); +} diff --git a/src/goals/CharacterInventory/CharInv/CharacterList/index.tsx b/src/goals/CharacterInventory/CharInv/CharacterList/index.tsx index 5608e58b5c..921c1989f0 100644 --- a/src/goals/CharacterInventory/CharInv/CharacterList/index.tsx +++ b/src/goals/CharacterInventory/CharInv/CharacterList/index.tsx @@ -1,5 +1,11 @@ import { ArrowDownward, ArrowUpward } from "@mui/icons-material"; -import { FormControl, Grid, InputLabel, MenuItem, Select } from "@mui/material"; +import { + FormControl, + Grid2, + InputLabel, + MenuItem, + Select, +} from "@mui/material"; import { ReactElement, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; @@ -42,53 +48,54 @@ export default function CharacterList(): ReactElement { return ( <> - - - - {t("charInventory.sortBy")} - - - - - { - /* The grid of character tiles */ - orderedChars.map((character) => ( - selectCharacter(character.character)} - fontHeight={fontHeight} - cardWidth={cardWidth} - /> - )) - } + + + {t("charInventory.sortBy")} + + + + + + { + /* The grid of character tiles */ + orderedChars.map((character) => ( + selectCharacter(character.character)} + fontHeight={fontHeight} + cardWidth={cardWidth} + /> + )) + } + ); } diff --git a/src/goals/CharacterInventory/CharInv/CharacterSetHeader.tsx b/src/goals/CharacterInventory/CharInv/CharacterSetHeader.tsx index 3820c844fe..db9bdbdd35 100644 --- a/src/goals/CharacterInventory/CharInv/CharacterSetHeader.tsx +++ b/src/goals/CharacterInventory/CharInv/CharacterSetHeader.tsx @@ -1,5 +1,5 @@ import { Help } from "@mui/icons-material"; -import { Grid, Tooltip, Typography } from "@mui/material"; +import { Tooltip, Typography } from "@mui/material"; import { ReactElement } from "react"; import { useTranslation } from "react-i18next"; @@ -9,20 +9,18 @@ export default function CharacterSetHeader(): ReactElement { const { t } = useTranslation(); return ( - - + {t("charInventory.characterSet.title")}{" "} + - {t("charInventory.characterSet.title")}{" "} - - - - - + + + ); } diff --git a/src/goals/CharacterInventory/CharInv/index.tsx b/src/goals/CharacterInventory/CharInv/index.tsx index f7d8a06a99..ddb85da517 100644 --- a/src/goals/CharacterInventory/CharInv/index.tsx +++ b/src/goals/CharacterInventory/CharInv/index.tsx @@ -1,39 +1,17 @@ -import { - Button, - Dialog, - DialogActions, - DialogContent, - DialogContentText, - DialogTitle, - Grid, -} from "@mui/material"; -import { ReactElement, useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; +import { Grid2, Stack } from "@mui/material"; +import { ReactElement, useEffect } from "react"; -import { LoadingButton } from "components/Buttons"; import CharacterDetail from "goals/CharacterInventory/CharInv/CharacterDetail"; import CharacterEntry from "goals/CharacterInventory/CharInv/CharacterEntry"; import CharacterList from "goals/CharacterInventory/CharInv/CharacterList"; import CharacterSetHeader from "goals/CharacterInventory/CharInv/CharacterSetHeader"; import { - exit, loadCharInvData, resetCharInv, setSelectedCharacter, - uploadInventory, } from "goals/CharacterInventory/Redux/CharacterInventoryActions"; import { useAppDispatch, useAppSelector } from "rootRedux/hooks"; import { type StoreState } from "rootRedux/types"; -import theme from "types/theme"; - -const idPrefix = "character-inventory"; -export const buttonIdCancel = `${idPrefix}-cancel-button`; -export const buttonIdSave = `${idPrefix}-save-button`; -export const dialogButtonIdNo = `${idPrefix}-cancel-dialog-no-button`; -export const dialogButtonIdYes = `${idPrefix}-cancel-dialog-yes-button`; -export const dialogIdCancel = `${idPrefix}-cancel-dialog`; -const dialogTextIdCancel = `${idPrefix}-cancel-dialog-text`; -const dialogTitleIdCancel = `${idPrefix}-cancel-dialog-title`; /** * Allows users to define a character inventory for a project @@ -45,11 +23,6 @@ export default function CharacterInventory(): ReactElement { (state: StoreState) => state.characterInventoryState.selectedCharacter ); - const [cancelDialogOpen, setCancelDialogOpen] = useState(false); - const [saveInProgress, setSaveInProgress] = useState(false); - - const { t } = useTranslation(); - useEffect(() => { dispatch(loadCharInvData()); @@ -57,99 +30,24 @@ export default function CharacterInventory(): ReactElement { () => dispatch(resetCharInv()); }, [dispatch]); - const save = async (): Promise => { - setSaveInProgress(true); - await dispatch(uploadInventory()); - }; - return ( - <> - - - - - - - - - - - {!!selectedCharacter && ( - dispatch(setSelectedCharacter(""))} - /> - )} - - - - {/* Submission buttons */} - - save(), - style: { margin: theme.spacing(1) }, - }} - > - {t("buttons.save")} - - - - - - - {/* "Are you sure?" dialog for the cancel button */} - setCancelDialogOpen(false)} - aria-labelledby="alert-dialog-title" - aria-describedby="alert-dialog-description" - > - - {t("charInventory.dialog.title")} - - - - {t("charInventory.dialog.content")} - - - - - - - - + + + + + + + + + + {!!selectedCharacter && ( + + dispatch(setSelectedCharacter(""))} + /> + + )} + ); } diff --git a/src/goals/CharacterInventory/CharInv/tests/index.test.tsx b/src/goals/CharacterInventory/CharInv/tests/index.test.tsx index e59662d4b2..620726a307 100644 --- a/src/goals/CharacterInventory/CharInv/tests/index.test.tsx +++ b/src/goals/CharacterInventory/CharInv/tests/index.test.tsx @@ -2,13 +2,8 @@ import { Provider } from "react-redux"; import { ReactTestRenderer, act, create } from "react-test-renderer"; import configureMockStore from "redux-mock-store"; -import CharInv, { - buttonIdCancel, - buttonIdSave, - dialogButtonIdNo, - dialogButtonIdYes, - dialogIdCancel, -} from "goals/CharacterInventory/CharInv"; +import CharInv from "goals/CharacterInventory/CharInv"; +import { CharInvCancelSaveIds } from "goals/CharacterInventory/CharInv/CharacterEntry"; import { defaultState as characterInventoryState } from "goals/CharacterInventory/Redux/CharacterInventoryReduxTypes"; // Replace Dialog with something that doesn't create portals, @@ -63,30 +58,42 @@ describe("CharInv", () => { it("saves inventory on save", async () => { expect(mockUploadInventory).toHaveBeenCalledTimes(0); - const saveButton = charMaster.root.findByProps({ id: buttonIdSave }); + const saveButton = charMaster.root.findByProps({ + id: CharInvCancelSaveIds.ButtonSave, + }); await act(async () => saveButton.props.onClick()); expect(mockUploadInventory).toHaveBeenCalledTimes(1); }); it("opens a dialogue on cancel, closes on no", async () => { - const cancelDialog = charMaster.root.findByProps({ id: dialogIdCancel }); + const cancelDialog = charMaster.root.findByProps({ + id: CharInvCancelSaveIds.DialogCancel, + }); expect(cancelDialog.props.open).toBeFalsy(); - const cancelButton = charMaster.root.findByProps({ id: buttonIdCancel }); + const cancelButton = charMaster.root.findByProps({ + id: CharInvCancelSaveIds.ButtonCancel, + }); await act(async () => cancelButton.props.onClick()); expect(cancelDialog.props.open).toBeTruthy(); - const noButton = charMaster.root.findByProps({ id: dialogButtonIdNo }); + const noButton = charMaster.root.findByProps({ + id: CharInvCancelSaveIds.DialogCancelButtonNo, + }); await act(async () => noButton.props.onClick()); expect(cancelDialog.props.open).toBeFalsy(); }); it("exits on cancel-yes", async () => { - const cancelButton = charMaster.root.findByProps({ id: buttonIdCancel }); + const cancelButton = charMaster.root.findByProps({ + id: CharInvCancelSaveIds.ButtonCancel, + }); await act(async () => cancelButton.props.onClick()); expect(mockExit).toHaveBeenCalledTimes(0); - const yesButton = charMaster.root.findByProps({ id: dialogButtonIdYes }); + const yesButton = charMaster.root.findByProps({ + id: CharInvCancelSaveIds.DialogCancelButtonYes, + }); await act(async () => yesButton.props.onClick()); expect(mockExit).toHaveBeenCalledTimes(1); }); diff --git a/src/goals/DefaultGoal/DisplayProgress.tsx b/src/goals/DefaultGoal/DisplayProgress.tsx index ea04b97a14..584a88b3ad 100644 --- a/src/goals/DefaultGoal/DisplayProgress.tsx +++ b/src/goals/DefaultGoal/DisplayProgress.tsx @@ -1,4 +1,4 @@ -import { Grid, LinearProgress, Paper, Typography } from "@mui/material"; +import { LinearProgress, Paper, Stack, Typography } from "@mui/material"; import { ReactElement } from "react"; import { useTranslation } from "react-i18next"; import { useSelector } from "react-redux"; @@ -31,16 +31,12 @@ export default function DisplayProgress(): ReactElement | null { return numSteps > 1 ? ( - - - - {t(stepTranslateId, { val1: currentStep + 1, val2: numSteps })} - - - - - - + + + {t(stepTranslateId, { val1: currentStep + 1, val2: numSteps })} + + + ) : null; } diff --git a/src/goals/MergeDuplicates/MergeDupsCompleted.tsx b/src/goals/MergeDuplicates/MergeDupsCompleted.tsx index 8f05fcfaa9..b286f4a837 100644 --- a/src/goals/MergeDuplicates/MergeDupsCompleted.tsx +++ b/src/goals/MergeDuplicates/MergeDupsCompleted.tsx @@ -1,5 +1,5 @@ import { ArrowRightAlt } from "@mui/icons-material"; -import { Card, Grid, Paper, Typography } from "@mui/material"; +import { Box, Card, Grid2, Paper, Stack, Typography } from "@mui/material"; import { ReactElement, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { useSelector } from "react-redux"; @@ -53,48 +53,42 @@ export function MergeChange(props: { change: MergeUndoIds }): ReactElement { const isDeletion = !change.parentIds.length; return ( - + {isDeletion && {t("mergeDups.undo.deleted")}} {change.childIds.map((id) => ( - + ))} {!isDeletion && ( <> - - - + + + {change.parentIds.map((id) => ( - + ))} )} - { - await undoMerge(change); - }} - /> - + + { + await undoMerge(change); + }} + /> + + ); } @@ -110,11 +104,7 @@ export function doWordsIncludeMerges( ); } -interface WordPaperProps { - wordId: string; -} - -function WordPaper(props: WordPaperProps): ReactElement { +function WordBox(props: { wordId: string }): ReactElement { const [word, setWord] = useState(); const [flag, setFlag] = useState(newFlag()); @@ -126,7 +116,7 @@ function WordPaper(props: WordPaperProps): ReactElement { }, [word]); return ( - + - - - - {word?.vernacular} - - - - - - + + + {word?.vernacular} + + +
{word?.senses?.map(SenseCard)}
-
+ ); } diff --git a/src/goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/SidebarDrop.tsx b/src/goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/SidebarDrop.tsx index dfbcb6b8c2..5d890cbddf 100644 --- a/src/goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/SidebarDrop.tsx +++ b/src/goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/SidebarDrop.tsx @@ -1,5 +1,5 @@ import { ArrowForwardIos, HelpOutline } from "@mui/icons-material"; -import { Grid, IconButton, Typography } from "@mui/material"; +import { Grid2, IconButton, Typography } from "@mui/material"; import { type ReactElement } from "react"; import { Droppable } from "react-beautiful-dnd"; @@ -29,21 +29,24 @@ export default function SidebarDrop(): ReactElement { {...providedDroppable.droppableProps} style={{ backgroundColor: "lightblue", height: "100%", padding: 20 }} > - + dispatch(setSidebar())} > + openUserGuide("goals.html#merge-a-sense")} > - + + {vernacular} + {sidebar.mergeSenses.map((mergeSense, index) => ( - - + + {(provided): ReactElement => (
@@ -252,36 +258,35 @@ export default function MergeDragDrop(): ReactElement {
)}
-
- - - {Object.keys(words).map((key) => ( - - - - ))} - - + + + + {Object.keys(words).map((key) => ( + + - {renderSidebar()} - setOverride(undefined)} - handleConfirm={onConfirmOverride} - /> - setSrcToDelete(undefined)} - handleConfirm={onConfirmDelete} - /> - - -
+ ))} + + + + {renderSidebar()} + setOverride(undefined)} + handleConfirm={onConfirmOverride} + /> + setSrcToDelete(undefined)} + handleConfirm={onConfirmDelete} + /> + + ); } diff --git a/src/goals/MergeDuplicates/MergeDupsStep/SaveDeferButtons.tsx b/src/goals/MergeDuplicates/MergeDupsStep/SaveDeferButtons.tsx index 50351851bb..5d912e6f3e 100644 --- a/src/goals/MergeDuplicates/MergeDupsStep/SaveDeferButtons.tsx +++ b/src/goals/MergeDuplicates/MergeDupsStep/SaveDeferButtons.tsx @@ -1,4 +1,4 @@ -import { Checkbox, FormControlLabel, Grid } from "@mui/material"; +import { Checkbox, FormControlLabel, Grid2 } from "@mui/material"; import { ReactElement, useState } from "react"; import { useTranslation } from "react-i18next"; @@ -13,7 +13,6 @@ import { import { asyncAdvanceStep } from "goals/Redux/GoalActions"; import { useAppDispatch, useAppSelector } from "rootRedux/hooks"; import { StoreState } from "rootRedux/types"; -import theme from "types/theme"; export default function SaveDeferButtons(): ReactElement { const dispatch = useAppDispatch(); @@ -52,43 +51,41 @@ export default function SaveDeferButtons(): ReactElement { }; return ( - - - - {t("buttons.saveAndContinue")} - - - {t("buttons.defer")} - - {hasProtected && ( - dispatch(toggleOverrideProtection())} - /> - } - label={t("mergeDups.helpText.protectedOverride")} - /> - )} - - + + + {t("buttons.saveAndContinue")} + + + + {t("buttons.defer")} + + + {hasProtected && ( + dispatch(toggleOverrideProtection())} + /> + } + label={t("mergeDups.helpText.protectedOverride")} + /> + )} + ); } diff --git a/src/goals/MergeDuplicates/MergeDupsStep/index.tsx b/src/goals/MergeDuplicates/MergeDupsStep/index.tsx index 6b1c2b01ac..d283f1c0b7 100644 --- a/src/goals/MergeDuplicates/MergeDupsStep/index.tsx +++ b/src/goals/MergeDuplicates/MergeDupsStep/index.tsx @@ -18,7 +18,13 @@ export default function MergeDupsStep(): ReactElement { return wordCount ? ( <> -
+
diff --git a/src/goals/ReviewEntries/ReviewEntriesCompleted.tsx b/src/goals/ReviewEntries/ReviewEntriesCompleted.tsx index 1fb4a23666..b4a2049f1c 100644 --- a/src/goals/ReviewEntries/ReviewEntriesCompleted.tsx +++ b/src/goals/ReviewEntries/ReviewEntriesCompleted.tsx @@ -1,5 +1,5 @@ import { ArrowRightAlt } from "@mui/icons-material"; -import { Grid, List, ListItem, Typography } from "@mui/material"; +import { Box, List, ListItem, Stack, Typography } from "@mui/material"; import { ReactElement, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { useSelector } from "react-redux"; @@ -65,31 +65,36 @@ function EditedEntry(props: { edit: EntryEdit }): ReactElement { return ( - - {!!oldWord && } - - + {!!oldWord && ( + + + + )} + + + + + + {!!newWord && ( + + + + )} + + + isInFrontier(newId)} + undo={() => undoEdit(props.edit)} /> - - {!!newWord && } - isInFrontier(newId)} - undo={() => undoEdit(props.edit)} - /> - + + ); } diff --git a/src/goals/ReviewEntries/ReviewEntriesTable/Cells/DomainsCell.tsx b/src/goals/ReviewEntries/ReviewEntriesTable/Cells/DomainsCell.tsx index 839c917f14..632cfd84b6 100644 --- a/src/goals/ReviewEntries/ReviewEntriesTable/Cells/DomainsCell.tsx +++ b/src/goals/ReviewEntries/ReviewEntriesTable/Cells/DomainsCell.tsx @@ -1,4 +1,4 @@ -import { Chip, Grid } from "@mui/material"; +import { Chip, Grid2 } from "@mui/material"; import { type ReactElement } from "react"; import { type SemanticDomain, type Sense } from "api/models"; @@ -19,12 +19,14 @@ export function gatherDomains(senses: Sense[]): SemanticDomain[] { export default function DomainsCell(props: CellProps): ReactElement { return ( - + {gatherDomains(props.word.senses).map((dom) => ( - - - + ))} - + ); } diff --git a/src/goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/EditDialog.tsx b/src/goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/EditDialog.tsx index 5f3428ccd1..b62dbbad16 100644 --- a/src/goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/EditDialog.tsx +++ b/src/goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/EditDialog.tsx @@ -13,10 +13,11 @@ import { Dialog, DialogContent, DialogTitle, - Grid, + Grid2, IconButton, MenuItem, Select, + Stack, type SelectChangeEvent, } from "@mui/material"; import { grey, yellow } from "@mui/material/colors"; @@ -351,151 +352,135 @@ export default function EditDialog(props: EditDialogProps): ReactElement { /> - - - {t("reviewEntries.columns.edit")} - {" : "} - {props.word.vernacular} - - + + {`${t("reviewEntries.columns.edit")} : ${props.word.vernacular}`} + +
+ - - +
+
+ - + {/* Vernacular */} - - - - - - setNewWord((prev) => ({ - ...prev, - vernacular: e.target.value, - })) - } - value={newWord.vernacular} - vernacular - /> - - - - - {/* Senses */} - - - 1 && ( - setShowSenses((prev) => !prev)} - > - {showSenses ? ( - - ) : ( - - )} - - ) + + + + + setNewWord((prev) => ({ + ...prev, + vernacular: e.target.value, + })) } - title={t("reviewEntries.columns.senses")} - /> - - - + + + + {/* Senses */} + + 1 && ( + setShowSenses((prev) => !prev)} + > + {showSenses ? ( + + ) : ( + + )} + + ) + } + title={t("reviewEntries.columns.senses")} + /> + + {/* Pronunciations */} - - - - - - } - audio={newAudio} - deleteAudio={delNewAudio} - replaceAudio={repNewAudio} - uploadAudio={uplNewAudio} - /> - - - + + + + + } + audio={newAudio} + deleteAudio={delNewAudio} + replaceAudio={repNewAudio} + uploadAudio={uplNewAudio} + /> + + {/* Note */} - - - + + + updateNoteText(e.target.value)} + value={newWord.note.text} /> - - updateNoteText(e.target.value)} - value={newWord.note.text} - /> - - - + + {/* Flag */} - - - - - - {newWord.flag.active ? ( - - ) : ( - - )} - - updateFlag(e.target.value)} - value={newWord.flag.active ? newWord.flag.text : ""} - /> - - - - + + + + + {newWord.flag.active ? ( + + ) : ( + + )} + + updateFlag(e.target.value)} + value={newWord.flag.active ? newWord.flag.text : ""} + /> + + +
diff --git a/src/goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/EditSenseDialog.tsx b/src/goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/EditSenseDialog.tsx index d00ee57c3b..71174cb60e 100644 --- a/src/goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/EditSenseDialog.tsx +++ b/src/goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/EditSenseDialog.tsx @@ -7,8 +7,9 @@ import { Dialog, DialogContent, DialogTitle, - Grid, + Grid2, IconButton, + Stack, Typography, } from "@mui/material"; import { grey, yellow } from "@mui/material/colors"; @@ -184,106 +185,96 @@ export default function EditSenseDialog( /> - - {t("reviewEntries.editSense")} - + + {t("reviewEntries.editSense")} + +
t.palette.success.main }} /> + t.palette.error.main }} /> - - +
+
+ - + {/* Definitions */} {definitionsEnabled && ( - - - - - - - - - )} - - {/* Glosses */} - - - + + - - + )} + + {/* Glosses */} + + + + + + {/* Part of Speech */} {grammaticalInfoEnabled && ( - - - - - {newSense.grammaticalInfo.catGroup === - GramCatGroup.Unspecified ? ( - - {t("grammaticalCategory.group.Unspecified")} - - ) : ( - - )} - - - - )} - - {/* Semantic Domains */} - - - + + - + {newSense.grammaticalInfo.catGroup === + GramCatGroup.Unspecified ? ( + + {t("grammaticalCategory.group.Unspecified")} + + ) : ( + + )} - - + )} + + {/* Semantic Domains */} + + + + + + +
@@ -450,21 +441,20 @@ function DomainList(props: DomainListProps): ReactElement { return ( <> - + {props.domains.length > 0 ? ( props.domains.map((domain, index) => ( - - deleteDomain(domain.id)} - /> - + deleteDomain(domain.id)} + /> )) ) : ( - + - + )} - + + setAddingDom(false)} diff --git a/src/goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/EditSensesCardContent.tsx b/src/goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/EditSensesCardContent.tsx index 18beddbe43..f02c685cf9 100644 --- a/src/goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/EditSensesCardContent.tsx +++ b/src/goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/EditSensesCardContent.tsx @@ -6,9 +6,9 @@ import { Edit, RestoreFromTrash, } from "@mui/icons-material"; -import { CardContent, Divider, Grid, Icon } from "@mui/material"; +import { CardContent, Divider, Grid2, Icon, Stack } from "@mui/material"; import { grey, yellow } from "@mui/material/colors"; -import { type ReactElement, useEffect, useState } from "react"; +import { Fragment, type ReactElement, useEffect, useState } from "react"; import { type Sense, Status } from "api/models"; import { IconButtonWithTooltip } from "components/Buttons"; @@ -55,35 +55,39 @@ export default function EditSensesCardContent( return ( {props.showSenses ? ( - <> + {props.newSenses.map((s, i) => ( - props.moveSense(i, i + 1) - : undefined - } - bumpSenseUp={i ? () => props.moveSense(i, i - 1) : undefined} - edited={changes[i]} - key={s.guid} - sense={s} - toggleSenseDeleted={() => props.toggleSenseDeleted(i)} - updateSense={props.updateOrAddSense} - /> + + props.moveSense(i, i + 1) + : undefined + } + bumpSenseUp={i ? () => props.moveSense(i, i - 1) : undefined} + edited={changes[i]} + sense={s} + toggleSenseDeleted={() => props.toggleSenseDeleted(i)} + updateSense={props.updateOrAddSense} + /> + + ))} + } onClick={() => setAddSense(true)} size="small" /> + setAddSense(false)} isOpen={addSense} save={props.updateOrAddSense} sense={newSense()} /> - + ) : ( - - {props.bumpSenseDown || props.bumpSenseUp ? ( - - - - : } - onClick={props.bumpSenseUp} - size="small" - /> - - - : } - onClick={props.bumpSenseDown} - size="small" - /> - - - - ) : null} - - - {deleted ? ( - - } - onClick={props.toggleSenseDeleted} - size="small" - /> - - ) : ( - <> - - } - onClick={ - sense.accessibility === Status.Protected - ? undefined - : props.toggleSenseDeleted - } - size="small" - textId={ - sense.accessibility === Status.Protected - ? "reviewEntries.deleteDisabled" - : undefined - } - /> - - - } - onClick={() => setEditing(true)} - size="small" - /> - - - )} - - - - + {props.bumpSenseDown || props.bumpSenseUp ? ( + + : } + onClick={props.bumpSenseUp} + size="small" + /> + + : } + onClick={props.bumpSenseDown} + size="small" /> - - setEditing(false)} - isOpen={editing} - save={props.updateSense} + + ) : null} + + + {deleted ? ( + } + onClick={props.toggleSenseDeleted} + size="small" + /> + ) : ( + <> + } + onClick={ + sense.accessibility === Status.Protected + ? undefined + : props.toggleSenseDeleted + } + size="small" + textId={ + sense.accessibility === Status.Protected + ? "reviewEntries.deleteDisabled" + : undefined + } + /> + + } + onClick={() => setEditing(true)} + size="small" + /> + + )} + + +
+ - - - +
+ + setEditing(false)} + isOpen={editing} + save={props.updateSense} + sense={sense} + /> + ); } diff --git a/src/goals/ReviewEntries/ReviewEntriesTable/Cells/PartOfSpeechCell.tsx b/src/goals/ReviewEntries/ReviewEntriesTable/Cells/PartOfSpeechCell.tsx index df0840d02a..604e1720a9 100644 --- a/src/goals/ReviewEntries/ReviewEntriesTable/Cells/PartOfSpeechCell.tsx +++ b/src/goals/ReviewEntries/ReviewEntriesTable/Cells/PartOfSpeechCell.tsx @@ -1,4 +1,4 @@ -import { Grid } from "@mui/material"; +import { Grid2 } from "@mui/material"; import { type ReactElement } from "react"; import { type GrammaticalInfo, type Sense } from "api/models"; @@ -18,12 +18,13 @@ function gatherGramInfo(senses: Sense[]): GrammaticalInfo[] { export default function PartOfSpeechCell(props: CellProps): ReactElement { return ( - + {gatherGramInfo(props.word.senses).map((gi) => ( - - - + ))} - + ); }