diff --git a/src/components/WordCard/SenseCard.tsx b/src/components/WordCard/SenseCard.tsx index c1c34806a7..91de0b4f90 100644 --- a/src/components/WordCard/SenseCard.tsx +++ b/src/components/WordCard/SenseCard.tsx @@ -17,7 +17,6 @@ export enum SenseCardLabel { interface SenseCardProps { bgColor?: string; - languages?: string[]; minimal?: boolean; provenance?: boolean; sense: Sense; @@ -43,11 +42,7 @@ export default function SenseCard(props: SenseCardProps): ReactElement { {/* Glosses and (if any) definitions */} - + {/* Semantic domains */} diff --git a/src/components/WordCard/SenseCardText.tsx b/src/components/WordCard/SenseCardText.tsx index 31c25587ca..59697240d9 100644 --- a/src/components/WordCard/SenseCardText.tsx +++ b/src/components/WordCard/SenseCardText.tsx @@ -8,8 +8,11 @@ import { Typography, } from "@mui/material"; import { ReactElement } from "react"; +import { shallowEqual } from "react-redux"; import { Sense } from "api/models"; +import { useAppSelector } from "rootRedux/hooks"; +import { type StoreState } from "rootRedux/types"; import { TypographyWithFont } from "utilities/fontComponents"; interface SenseInLanguage { @@ -36,25 +39,26 @@ function getSenseInLanguage( function getSenseInLanguages( sense: Sense, - languages?: string[] + languages: string[] ): SenseInLanguage[] { - if (!languages) { - languages = sense.glosses.map((g) => g.language); - languages.push(...sense.definitions.map((d) => d.language)); - languages = [...new Set(languages)]; - } return languages.map((l) => getSenseInLanguage(sense, l)); } interface SenseCardTextProps { sense: Sense; hideDefs?: boolean; - languages?: string[]; } // Show glosses and (if not hideDefs) definitions. export default function SenseCardText(props: SenseCardTextProps): ReactElement { - const senseTextInLangs = getSenseInLanguages(props.sense, props.languages); + const analysisLangs = useAppSelector( + (state: StoreState) => + state.currentProjectState.project.analysisWritingSystems.map( + (ws) => ws.bcp47 + ), + shallowEqual + ); + const senseTextInLangs = getSenseInLanguages(props.sense, analysisLangs); return ( diff --git a/src/components/WordCard/SensesTextSummary.tsx b/src/components/WordCard/SensesTextSummary.tsx index 8d00300185..394e01cf62 100644 --- a/src/components/WordCard/SensesTextSummary.tsx +++ b/src/components/WordCard/SensesTextSummary.tsx @@ -1,6 +1,9 @@ import { type ReactElement } from "react"; +import { shallowEqual } from "react-redux"; import { type Sense } from "api/models"; +import { useAppSelector } from "rootRedux/hooks"; +import { type StoreState } from "rootRedux/types"; import { TypographyWithFont } from "utilities/fontComponents"; interface SensesTextSummaryProp { @@ -16,16 +19,49 @@ export default function SensesTextSummary( const interSenseSep = " | "; const intraSenseSep = "; "; + const analysisLangs = useAppSelector( + (state: StoreState) => + state.currentProjectState.project.analysisWritingSystems.map( + (ws) => ws.bcp47 + ), + shallowEqual + ); + const typographies: ReactElement[] = []; props.senses.forEach((sense) => { let texts: string[]; + let lang: string | undefined; switch (props.definitionsOrGlosses) { case "definitions": - texts = sense.definitions.map((d) => d.text.trim()); + if (analysisLangs.length) { + texts = analysisLangs.flatMap((l) => + sense.definitions + .filter((d) => d.language === l) + .map((d) => d.text.trim()) + ); + lang = analysisLangs.find((l) => + sense.definitions.some((d) => d.language === l && d.text.trim()) + ); + } else { + texts = sense.definitions.map((d) => d.text.trim()); + lang = sense.definitions.find((d) => d.text.trim())?.language; + } break; case "glosses": - texts = sense.glosses.map((g) => g.def.trim()); + if (analysisLangs.length) { + texts = analysisLangs.flatMap((l) => + sense.glosses + .filter((g) => g.language === l) + .map((g) => g.def.trim()) + ); + lang = analysisLangs.find((l) => + sense.glosses.some((g) => g.language === l && g.def.trim()) + ); + } else { + texts = sense.glosses.map((g) => g.def.trim()); + lang = sense.glosses.find((g) => g.def.trim())?.language; + } break; } let text = texts.filter((t) => t).join(intraSenseSep); @@ -49,16 +85,6 @@ export default function SensesTextSummary( ); } - // Use the analysis language of the first non-empty definition/gloss, if any. - let lang: string | undefined; - switch (props.definitionsOrGlosses) { - case "definitions": - lang = sense.definitions.find((d) => d.text.trim())?.language; - break; - case "glosses": - lang = sense.glosses.find((g) => g.def.trim())?.language; - break; - } typographies.push( {senses.map((s) => ( - + ))} ) : ( diff --git a/src/goals/CharacterInventory/tests/CharInvCompleted.test.tsx b/src/goals/CharacterInventory/tests/CharInvCompleted.test.tsx index 4926555254..75116cd658 100644 --- a/src/goals/CharacterInventory/tests/CharInvCompleted.test.tsx +++ b/src/goals/CharacterInventory/tests/CharInvCompleted.test.tsx @@ -13,8 +13,7 @@ import { type FindAndReplaceChange, defaultCharInvChanges, } from "goals/CharacterInventory/CharacterInventoryTypes"; -import { defaultState } from "goals/Redux/GoalReduxTypes"; -import { type StoreState } from "rootRedux/types"; +import { defaultState, type StoreState } from "rootRedux/types"; import { newWord as mockWord } from "types/word"; jest.mock("backend", () => ({ @@ -38,10 +37,11 @@ const mockWordChanges: FindAndReplaceChange = { replace: "q", words: { [mockWordKeys[0]]: "newA", [mockWordKeys[1]]: "newB" }, }; -const mockState = (changes?: CharInvChanges): Partial => ({ +const mockState = (changes?: CharInvChanges): StoreState => ({ + ...defaultState, goalsState: { - ...defaultState, - currentGoal: { ...defaultState.currentGoal, changes }, + ...defaultState.goalsState, + currentGoal: { ...defaultState.goalsState.currentGoal, changes }, }, }); diff --git a/src/goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/DragSense.tsx b/src/goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/DragSense.tsx index 15f0eef8af..3cd3353aaa 100644 --- a/src/goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/DragSense.tsx +++ b/src/goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/DragSense.tsx @@ -1,6 +1,7 @@ import { Draggable } from "@hello-pangea/dnd"; import { Card } from "@mui/material"; import { type ReactElement, useCallback, useEffect, useState } from "react"; +import { shallowEqual } from "react-redux"; import { trashId } from "goals/MergeDuplicates/MergeDupsStep/MergeDragDrop/MergeDragDropTypes"; import SenseCardContent from "goals/MergeDuplicates/MergeDupsStep/SenseCardContent"; @@ -20,27 +21,8 @@ interface DragSenseProps { senseRef: MergeTreeReference; } -function arraysEqual(arr1: T[], arr2: T[]): boolean { - if (arr1.length !== arr2.length) { - return false; - } - for (let i = 0; i < arr1.length; i++) { - if (arr1[i] !== arr2[i]) { - return false; - } - } - return true; -} - export default function DragSense(props: DragSenseProps): ReactElement { const [duplicateCount, setDuplicateCount] = useState(1); - const analysisLangs = useAppSelector( - (state: StoreState) => - state.currentProjectState.project.analysisWritingSystems.map( - (ws) => ws.bcp47 - ), - arraysEqual - ); const dispatch = useAppDispatch(); const overrideProtection = useAppSelector( (state: StoreState) => state.mergeDuplicateGoal.overrideProtection @@ -78,7 +60,7 @@ export default function DragSense(props: DragSenseProps): ReactElement { if ( isInSidebar && - !arraysEqual( + !shallowEqual( sidebar.mergeSenses.map((m) => m.sense.guid), props.mergeSenses.map((m) => m.sense.guid) ) @@ -122,7 +104,6 @@ export default function DragSense(props: DragSenseProps): ReactElement { > s.sense)} - languages={analysisLangs} toggleFunction={toggleSidebar} /> diff --git a/src/goals/MergeDuplicates/MergeDupsStep/SenseCardContent.tsx b/src/goals/MergeDuplicates/MergeDupsStep/SenseCardContent.tsx index 926762afc2..c102dbfc62 100644 --- a/src/goals/MergeDuplicates/MergeDupsStep/SenseCardContent.tsx +++ b/src/goals/MergeDuplicates/MergeDupsStep/SenseCardContent.tsx @@ -12,7 +12,6 @@ import { combineSenses } from "goals/MergeDuplicates/Redux/reducerUtilities"; interface SenseCardContentProps { senses: Sense[]; isCompleted?: boolean; - languages?: string[]; sidebar?: boolean; toggleFunction?: () => void; } @@ -73,7 +72,7 @@ export default function SenseCardContent( )} {/* List glosses and (if any) definitions. */} - + {/* List semantic domains. */} diff --git a/src/goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/tests/EditSensesCardContent.test.tsx b/src/goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/tests/EditSensesCardContent.test.tsx index 32bb48bca4..a3337d728a 100644 --- a/src/goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/tests/EditSensesCardContent.test.tsx +++ b/src/goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/tests/EditSensesCardContent.test.tsx @@ -1,11 +1,14 @@ import "@testing-library/jest-dom"; import { act, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; +import { Provider } from "react-redux"; +import configureMockStore from "redux-mock-store"; import { GramCatGroup, Sense, Status } from "api/models"; import EditSensesCardContent, { EditSensesId, } from "goals/ReviewEntries/ReviewEntriesTable/Cells/EditCell/EditSensesCardContent"; +import { defaultState } from "rootRedux/types"; import { newSemanticDomain } from "types/semanticDomain"; import { newDefinition, newSense } from "types/word"; @@ -48,14 +51,16 @@ const mockSenses = (): Sense[] => [ const renderEditSensesCardContent = async (showSenses = true): Promise => await act(async () => { render( - mockMoveSense(from, to)} - newSenses={mockSenses()} - oldSenses={mockSenses()} - showSenses={showSenses} - toggleSenseDeleted={mockToggleSenseDeleted} - updateOrAddSense={mockUpdateOrAddSense} - /> + + mockMoveSense(from, to)} + newSenses={mockSenses()} + oldSenses={mockSenses()} + showSenses={showSenses} + toggleSenseDeleted={mockToggleSenseDeleted} + updateOrAddSense={mockUpdateOrAddSense} + /> + ); });