From 097f4af26771fabba3758e771d50253922b9bdc6 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 21 Aug 2024 12:37:47 -0400 Subject: [PATCH] [DataEntryTable] Distinguish between new and updated words (#3307) --- .../DataEntry/DataEntryTable/index.tsx | 24 ++++++++++++------- .../DataEntryTable/tests/index.test.tsx | 20 ++++++++++++---- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/components/DataEntry/DataEntryTable/index.tsx b/src/components/DataEntry/DataEntryTable/index.tsx index bf0a0b5da4..734d75b636 100644 --- a/src/components/DataEntry/DataEntryTable/index.tsx +++ b/src/components/DataEntry/DataEntryTable/index.tsx @@ -69,8 +69,9 @@ interface SenseSwitch { } export interface WordAccess { - word: Word; + isNew: boolean; senseGuid: string; + word: Word; } enum DefunctStatus { @@ -335,7 +336,7 @@ export default function DataEntryTable( const recentWords = [...prevState.recentWords]; word.senses.forEach((s) => { if (s.semanticDomains.some((dom) => dom.id === domId)) { - recentWords.push({ word, senseGuid: s.guid }); + recentWords.push({ isNew: false, senseGuid: s.guid, word }); } }); return { ...prevState, recentWords }; @@ -358,6 +359,7 @@ export default function DataEntryTable( if (replaceIndex > -1) { deleteCount = 1; insertIndex = replaceIndex; + wordAccess.isNew = recentWords[replaceIndex].isNew; } if (insertIndex > -1 && insertIndex < recentWords.length) { @@ -392,7 +394,7 @@ export default function DataEntryTable( const replaceInDisplay = (oldId: string, word: Word): void => { setState((prevState) => { const recentWords = prevState.recentWords.map((a) => - a.word.id === oldId ? { word, senseGuid: a.senseGuid } : a + a.word.id === oldId ? { ...a, word } : a ); return { ...prevState, isFetchingFrontier: true, recentWords }; }); @@ -738,7 +740,10 @@ export default function DataEntryTable( if (wordId !== word.id) { word = await backend.getWord(wordId); } - addToDisplay({ word, senseGuid: word.senses[0].guid }, insertIndex); + addToDisplay( + { isNew: true, senseGuid: word.senses[0].guid, word }, + insertIndex + ); }, [addAudiosToBackend, addDuplicateWord] ); @@ -754,7 +759,7 @@ export default function DataEntryTable( const wordId = await addAudiosToBackend(word.id, audio); word = await backend.getWord(wordId); } - addToDisplay({ word, senseGuid }); + addToDisplay({ isNew: false, senseGuid, word }); }; /** Reset the entry table. If there is an un-submitted word then submit it. */ @@ -880,7 +885,7 @@ export default function DataEntryTable( /** Retract a recent entry. */ const undoRecentEntry = useCallback( async (eIndex: number): Promise => { - const { word, senseGuid } = state.recentWords[eIndex]; + const { isNew, senseGuid, word } = state.recentWords[eIndex]; const sIndex = word.senses.findIndex((s) => s.guid === senseGuid); if (sIndex === -1) { throw new Error("Entry does not have specified sense."); @@ -890,8 +895,9 @@ export default function DataEntryTable( const senses = [...word.senses]; const oldSense = senses[sIndex]; const oldDoms = oldSense.semanticDomains; - if (oldDoms.length > 1) { - // If there is more than one semantic domain in this sense, only remove the domain. + if (oldDoms.length > 1 || !isNew) { + // If there is more than one domain in this sense or the entry isn't new, + // only remove the domain. const doms = oldDoms.filter((d) => d.id !== props.semanticDomain.id); const newSense: Sense = { ...oldSense, semanticDomains: doms }; senses.splice(sIndex, 1, newSense); @@ -901,7 +907,7 @@ export default function DataEntryTable( senses.splice(sIndex, 1); await updateWordInBackend({ ...word, senses }); } else { - // Since this is the only sense, delete the word. + // Since this is the only sense in a new word, delete the word. await backend.deleteFrontierWord(word.id); } }, diff --git a/src/components/DataEntry/DataEntryTable/tests/index.test.tsx b/src/components/DataEntry/DataEntryTable/tests/index.test.tsx index d733021b16..1e730b1766 100644 --- a/src/components/DataEntry/DataEntryTable/tests/index.test.tsx +++ b/src/components/DataEntry/DataEntryTable/tests/index.test.tsx @@ -245,7 +245,11 @@ describe("DataEntryTable", () => { describe("updateEntryGloss", () => { it("throws error when entry doesn't have sense with specified guid", () => { - const entry: WordAccess = { word: newWord(), senseGuid: "gibberish" }; + const entry: WordAccess = { + isNew: true, + senseGuid: "gibberish", + word: newWord(), + }; expect(() => updateEntryGloss(entry, "def", "semDomId", "en")).toThrow(); }); @@ -253,7 +257,11 @@ describe("DataEntryTable", () => { const senseIndex = 1; const sense = mockMultiWord.senses[senseIndex]; sense.semanticDomains = [mockSemDom]; - const entry: WordAccess = { word: mockMultiWord, senseGuid: sense.guid }; + const entry: WordAccess = { + isNew: false, + senseGuid: sense.guid, + word: mockMultiWord, + }; const def = "newGlossDef"; const expectedGloss: Gloss = { ...sense.glosses[0], def }; @@ -271,7 +279,11 @@ describe("DataEntryTable", () => { const targetGloss = newGloss("target language", "tl"); sense.glosses = [...sense.glosses, targetGloss]; sense.semanticDomains = [mockSemDom]; - const entry: WordAccess = { word: mockMultiWord, senseGuid: sense.guid }; + const entry: WordAccess = { + isNew: false, + senseGuid: sense.guid, + word: mockMultiWord, + }; const def = "newGlossDef"; const expectedGloss: Gloss = { ...targetGloss, def }; @@ -291,7 +303,7 @@ describe("DataEntryTable", () => { const sense = word.senses[0]; const otherDomain: SemanticDomain = { ...mockSemDom, id: "otherId" }; sense.semanticDomains = [otherDomain, mockSemDom]; - const entry: WordAccess = { word, senseGuid: sense.guid }; + const entry: WordAccess = { isNew: false, senseGuid: sense.guid, word }; const def = "newGlossDef"; const oldSense: Sense = { ...sense, semanticDomains: [otherDomain] };