Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions src/components/WordCard/SenseCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export enum SenseCardLabel {

interface SenseCardProps {
bgColor?: string;
languages?: string[];
minimal?: boolean;
provenance?: boolean;
sense: Sense;
Expand All @@ -43,11 +42,7 @@ export default function SenseCard(props: SenseCardProps): ReactElement {
</div>

{/* Glosses and (if any) definitions */}
<SenseCardText
hideDefs={props.minimal}
languages={props.languages}
sense={props.sense}
/>
<SenseCardText hideDefs={props.minimal} sense={props.sense} />

{/* Semantic domains */}
<DomainChipsGrid provenance={props.provenance} semDoms={semDoms} />
Expand Down
20 changes: 12 additions & 8 deletions src/components/WordCard/SenseCardText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 (
<Table padding="none">
Expand Down
50 changes: 38 additions & 12 deletions src/components/WordCard/SensesTextSummary.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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);
Expand All @@ -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(
<TypographyWithFont
analysis
Expand Down
10 changes: 2 additions & 8 deletions src/components/WordCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import { TypographyWithFont } from "utilities/fontComponents";
import { getLocalizedDateTimeString } from "utilities/utilities";

interface WordCardProps {
languages?: string[];
provenance?: boolean;
word: Word;
}
Expand All @@ -40,7 +39,7 @@ export enum WordCardLabel {
}

export default function WordCard(props: WordCardProps): ReactElement {
const { languages, provenance, word } = props;
const { provenance, word } = props;
const { audio, editedBy, flag, id, note, senses } = word;
const [full, setFull] = useState(false);
const [username, setUsername] = useState("");
Expand Down Expand Up @@ -125,12 +124,7 @@ export default function WordCard(props: WordCardProps): ReactElement {
{full ? (
<Stack spacing={1}>
{senses.map((s) => (
<SenseCard
key={s.guid}
languages={languages}
provenance={provenance}
sense={s}
/>
<SenseCard key={s.guid} provenance={provenance} sense={s} />
))}
</Stack>
) : (
Expand Down
10 changes: 5 additions & 5 deletions src/goals/CharacterInventory/tests/CharInvCompleted.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => ({
Expand All @@ -38,10 +37,11 @@ const mockWordChanges: FindAndReplaceChange = {
replace: "q",
words: { [mockWordKeys[0]]: "newA", [mockWordKeys[1]]: "newB" },
};
const mockState = (changes?: CharInvChanges): Partial<StoreState> => ({
const mockState = (changes?: CharInvChanges): StoreState => ({
...defaultState,
goalsState: {
...defaultState,
currentGoal: { ...defaultState.currentGoal, changes },
...defaultState.goalsState,
currentGoal: { ...defaultState.goalsState.currentGoal, changes },
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -20,27 +21,8 @@ interface DragSenseProps {
senseRef: MergeTreeReference;
}

function arraysEqual<T>(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<number>(1);
const analysisLangs = useAppSelector(
(state: StoreState) =>
state.currentProjectState.project.analysisWritingSystems.map(
(ws) => ws.bcp47
),
arraysEqual<string>
);
const dispatch = useAppDispatch();
const overrideProtection = useAppSelector(
(state: StoreState) => state.mergeDuplicateGoal.overrideProtection
Expand Down Expand Up @@ -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)
)
Expand Down Expand Up @@ -122,7 +104,6 @@ export default function DragSense(props: DragSenseProps): ReactElement {
>
<SenseCardContent
senses={props.mergeSenses.map((s) => s.sense)}
languages={analysisLangs}
toggleFunction={toggleSidebar}
/>
</Card>
Expand Down
3 changes: 1 addition & 2 deletions src/goals/MergeDuplicates/MergeDupsStep/SenseCardContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { combineSenses } from "goals/MergeDuplicates/Redux/reducerUtilities";
interface SenseCardContentProps {
senses: Sense[];
isCompleted?: boolean;
languages?: string[];
sidebar?: boolean;
toggleFunction?: () => void;
}
Expand Down Expand Up @@ -73,7 +72,7 @@ export default function SenseCardContent(
)}
</div>
{/* List glosses and (if any) definitions. */}
<SenseCardText languages={props.languages} sense={sense} />
<SenseCardText sense={sense} />
{/* List semantic domains. */}
<DomainChipsGrid semDoms={semDoms} />
</CardContent>
Expand Down
Original file line number Diff line number Diff line change
@@ -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";

Expand Down Expand Up @@ -48,14 +51,16 @@ const mockSenses = (): Sense[] => [
const renderEditSensesCardContent = async (showSenses = true): Promise<void> =>
await act(async () => {
render(
<EditSensesCardContent
moveSense={(from: number, to: number) => mockMoveSense(from, to)}
newSenses={mockSenses()}
oldSenses={mockSenses()}
showSenses={showSenses}
toggleSenseDeleted={mockToggleSenseDeleted}
updateOrAddSense={mockUpdateOrAddSense}
/>
<Provider store={configureMockStore()(defaultState)}>
<EditSensesCardContent
moveSense={(from: number, to: number) => mockMoveSense(from, to)}
newSenses={mockSenses()}
oldSenses={mockSenses()}
showSenses={showSenses}
toggleSenseDeleted={mockToggleSenseDeleted}
updateOrAddSense={mockUpdateOrAddSense}
/>
</Provider>
);
});

Expand Down
Loading