diff --git a/src/models/subs/index.ts b/src/models/subs/index.ts index ae73daa..4e1ef2a 100644 --- a/src/models/subs/index.ts +++ b/src/models/subs/index.ts @@ -42,8 +42,6 @@ export const updatePrevCurrentSubsFx = createEffect((subs) => su export const updateCustomSubsFx = createEffect((subs) => subs); export const $subsDelay = createStore(0); -export const $activePhrasalVerb = createStore(null); -export const activePhrasalVerbChanged = createEvent(); export const subsDelayButtonPressed = createEvent(); export const subsDelayChangeFx = createEffect((value) => value); export const subsResyncFx = createEffect< diff --git a/src/models/subs/init.ts b/src/models/subs/init.ts index e5d0dcf..24504d5 100644 --- a/src/models/subs/init.ts +++ b/src/models/subs/init.ts @@ -4,8 +4,6 @@ import { $rawSubs, $subs, $subsDelay, - $activePhrasalVerb, - activePhrasalVerbChanged, esSubsChanged, fetchSubsFx, resetSubs, @@ -86,7 +84,6 @@ $currentSubs.on([updateCurrentSubsFx.doneData, autoPauseFx.doneData], (oldSubs, ); $subsDelay.on(subsDelayChangeFx.doneData, (_, newSubsDelay) => newSubsDelay); -$activePhrasalVerb.on(activePhrasalVerbChanged, (_, phrasalVerb) => phrasalVerb); $subsLanguage.on(subsLanguageDetectFx.doneData, (_, lang) => lang); -debug($rawSubs, $subs, $subsDelay, subsResyncFx, fetchSubsFx, $activePhrasalVerb, autoPauseFx.doneData, $currentSubs); +debug($rawSubs, $subs, $subsDelay, subsResyncFx, fetchSubsFx, autoPauseFx.doneData, $currentSubs); diff --git a/src/models/translations/index.ts b/src/models/translations/index.ts index 9199ca8..d56ff9c 100644 --- a/src/models/translations/index.ts +++ b/src/models/translations/index.ts @@ -1,16 +1,44 @@ import { createEffect, createEvent, createStore, sample, split } from "effector"; import { debug } from "patronum"; -import { TPartOfSpeach, TTranslateAlternative, TWordTranslation, TWordTranslationItem } from "../types"; +import { + TPartOfSpeach, + TPhrasalVerb, + TSub, + TTranslateAlternative, + TWordTranslation, + TWordTranslationItem, +} from "../types"; import { $translateLanguage } from "../settings"; import { googleNumberToPartOfSpeach } from "@src/utils/googleNumberToPartOfSpeach"; +import { createGate } from "effector-react"; +import { findPhrasalVerbs } from "@src/utils/findPhrasalVerbs"; +import { $currentSubs, $subsLanguage } from "../subs"; export const $wordTranslations = createStore([]); +export const $wordTranslationsPendings = createStore>({}); +export const WordTranslationsGate = createGate("WordTranslationsGate"); export const $currentWordTranslation = createStore(null); export const requestWordTranslation = createEvent(); -export const cleanWordTranslation = createEvent(); + +export const $currentPhrasalVerbs = createStore([]); +export const $currentPhrasalVerb = createStore(null); +export const $findPhrasalVerbsPendings = createStore>({}); +export const $findCurrentPhrasalVerbPendings = createStore>({}); +export const SubItemGate = createGate<{ text: string }>("SubItemGate"); +export const findPhrasalVerbsFx = createEffect<{ subs: TSub[] }, TPhrasalVerb[]>(({ subs }) => + subs.flatMap((sub) => findPhrasalVerbs(sub.cleanedText)) +); +export const subItemMouseEntered = createEvent(); +export const subItemMouseLeft = createEvent(); +export const findCurrentPhrasalVerbFx = createEffect< + { phrasalVerbs: TPhrasalVerb[]; text: string }, + TPhrasalVerb | null +>(({ phrasalVerbs, text }) => phrasalVerbs.find((phrasalVerb) => phrasalVerb.text.includes(text))); export const $currentSubTranslation = createStore(null); +export const $subTranslationPendings = createStore>({}); +export const SubTranslationGate = createGate("SubTranslationGate"); export const requestSubTranslation = createEvent(); export const cleanSubTranslation = createEvent(); export const fetchSubTranslationFx = createEffect<{ source: string; language: string }, string>( @@ -110,11 +138,24 @@ $currentWordTranslation.on( [fetchWordTranslationFx.doneData, updateCurrentWordTranslationFx.doneData], (_, translation) => translation ); -$currentWordTranslation.reset(cleanWordTranslation); +$currentWordTranslation.reset(WordTranslationsGate.close); $wordTranslations.on(fetchWordTranslationFx.doneData, (allTranslation, translation) => [ ...allTranslation, translation, ]); +$wordTranslationsPendings.on(fetchWordTranslationFx, (pendings, { source }) => ({ + ...pendings, + [source]: true, +})); +$wordTranslationsPendings.on(fetchWordTranslationFx.finally, (pendings, { params: { source } }) => { + const copy = { ...pendings }; + delete copy[source]; + return copy; +}); +sample({ + clock: WordTranslationsGate.open, + target: requestWordTranslation, +}); sample({ clock: requestSubTranslation, @@ -124,16 +165,68 @@ sample({ }); $currentSubTranslation.on(fetchSubTranslationFx.doneData, (_, translation) => translation); -$currentSubTranslation.reset(cleanSubTranslation); +$currentSubTranslation.reset(SubTranslationGate.close); +$subTranslationPendings.on(fetchSubTranslationFx, (pendings, { source }) => ({ + ...pendings, + [source]: true, +})); +$subTranslationPendings.on(fetchSubTranslationFx.finally, (pendings, { params: { source } }) => { + const copy = { ...pendings }; + delete copy[source]; + return copy; +}); +sample({ + clock: SubTranslationGate.open, + target: requestSubTranslation, +}); + +$currentPhrasalVerbs.on(findPhrasalVerbsFx.doneData, (_, phrasalVerbs) => phrasalVerbs); +$findPhrasalVerbsPendings.on(findPhrasalVerbsFx, (pendings, { subs }) => ({ + ...pendings, + [subs[0].cleanedText]: true, +})); +$findPhrasalVerbsPendings.on(findPhrasalVerbsFx.finally, (pendings, { params: { subs } }) => { + const copy = { ...pendings }; + delete copy[subs[0].cleanedText]; + return copy; +}); +sample({ + clock: $currentSubs, + source: { translateLanguage: $translateLanguage, subsLanguage: $subsLanguage }, + filter: ({ translateLanguage, subsLanguage }, subs) => + translateLanguage === "ru" && subsLanguage === "en" && subs.length > 0, + fn: (_, subs) => ({ subs }), + target: findPhrasalVerbsFx, +}); + +$findCurrentPhrasalVerbPendings.on(findCurrentPhrasalVerbFx, (pendings, { text }) => ({ + ...pendings, + [text]: true, +})); +$findCurrentPhrasalVerbPendings.on(findCurrentPhrasalVerbFx.finally, (pendings, { params: { text } }) => { + const copy = { ...pendings }; + delete copy[text]; + return copy; +}); +$currentPhrasalVerb.on(findCurrentPhrasalVerbFx.doneData, (_, phrasalVerb) => phrasalVerb); +$currentPhrasalVerb.reset(subItemMouseLeft); +sample({ + clock: subItemMouseEntered, + source: { phrasalVerbs: $currentPhrasalVerbs }, + fn: ({ phrasalVerbs }, text) => ({ phrasalVerbs, text }), + target: findCurrentPhrasalVerbFx, +}); debug( $wordTranslations, $currentWordTranslation, requestWordTranslation, - cleanWordTranslation, fetchWordTranslationFx.doneData, $currentSubTranslation, requestSubTranslation, cleanSubTranslation, - fetchSubTranslationFx.doneData + fetchSubTranslationFx.doneData, + findCurrentPhrasalVerbFx, + $currentPhrasalVerb, + $currentPhrasalVerbs ); diff --git a/src/pages/content/components/Subs/PhrasalVerbTranslation.tsx b/src/pages/content/components/Subs/PhrasalVerbTranslation.tsx index 1923e1b..f89a69a 100644 --- a/src/pages/content/components/Subs/PhrasalVerbTranslation.tsx +++ b/src/pages/content/components/Subs/PhrasalVerbTranslation.tsx @@ -2,16 +2,14 @@ import { FC, useEffect, useState } from "react"; import { useUnit } from "effector-react"; import { TPhrasalVerb } from "@src/models/types"; -import { cleanWordTranslation, requestWordTranslation } from "@src/models/translations"; import { $learningService } from "@src/models/settings"; -import { $subsLanguage } from "@src/models/subs"; import ILearningService from "@src/learning-service/learningService"; import { getLearningService } from "@src/utils/getLearningService"; import toast from "react-hot-toast"; import { PlusIcon } from "./assets/PlusIcon"; export const PhrasalVerbTranslation: FC<{ phrasalVerb: TPhrasalVerb }> = ({ phrasalVerb }) => { - const [learningService] = useUnit([$learningService, requestWordTranslation, cleanWordTranslation, $subsLanguage]); + const [learningService] = useUnit([$learningService]); const [service, setService] = useState(null); diff --git a/src/pages/content/components/Subs/SubFullTranslation.tsx b/src/pages/content/components/Subs/SubFullTranslation.tsx index e73809f..ce3c484 100644 --- a/src/pages/content/components/Subs/SubFullTranslation.tsx +++ b/src/pages/content/components/Subs/SubFullTranslation.tsx @@ -1,23 +1,13 @@ -import { FC, useEffect } from "react"; -import { useUnit } from "effector-react"; +import { FC } from "react"; +import { useGate, useUnit } from "effector-react"; -import { $currentSubTranslation, cleanSubTranslation, requestSubTranslation } from "@src/models/translations"; +import { $currentSubTranslation, $subTranslationPendings, SubTranslationGate } from "@src/models/translations"; export const SubFullTranslation: FC<{ text: string }> = ({ text }) => { - const [currentSubTranslation, handleRequestSubTranslation, handleCleanSubTranslation] = useUnit([ - $currentSubTranslation, - requestSubTranslation, - cleanSubTranslation, - ]); + useGate(SubTranslationGate, text); + const [currentSubTranslation, subTranslationPendings] = useUnit([$currentSubTranslation, $subTranslationPendings]); - useEffect(() => { - handleRequestSubTranslation(text); - return () => { - handleCleanSubTranslation(); - }; - }, []); - - if (!currentSubTranslation) { + if (!currentSubTranslation || subTranslationPendings[text]) { return null; } diff --git a/src/pages/content/components/Subs/SubItemTranslation.tsx b/src/pages/content/components/Subs/SubItemTranslation.tsx index c3a39f0..617b713 100644 --- a/src/pages/content/components/Subs/SubItemTranslation.tsx +++ b/src/pages/content/components/Subs/SubItemTranslation.tsx @@ -1,8 +1,8 @@ import { FC, useEffect, useState } from "react"; -import { useUnit } from "effector-react"; +import { useGate, useUnit } from "effector-react"; import { $learningService } from "@src/models/settings"; -import { $currentWordTranslation, cleanWordTranslation, requestWordTranslation } from "@src/models/translations"; +import { $currentWordTranslation, $wordTranslationsPendings, WordTranslationsGate } from "@src/models/translations"; import toast from "react-hot-toast"; import { SoundIcon } from "./assets/SoundIcon"; import { PlusIcon } from "./assets/PlusIcon"; @@ -18,13 +18,13 @@ import { $subsLanguage } from "@src/models/subs"; import { getLearningService } from "@src/utils/getLearningService"; export const SubItemTranslation: FC<{ text: string }> = ({ text }) => { - const [ - currentWordTranslation, - learningService, - handleRequestWordTranslation, - handleCleanWordTranslation, - subsLanguage, - ] = useUnit([$currentWordTranslation, $learningService, requestWordTranslation, cleanWordTranslation, $subsLanguage]); + useGate(WordTranslationsGate, text); + const [currentWordTranslation, learningService, subsLanguage, wordTranslationsPendings] = useUnit([ + $currentWordTranslation, + $learningService, + $subsLanguage, + $wordTranslationsPendings, + ]); const [service, setService] = useState(null); @@ -32,14 +32,7 @@ export const SubItemTranslation: FC<{ text: string }> = ({ text }) => { setService(getLearningService(learningService)); }, [learningService]); - useEffect(() => { - handleRequestWordTranslation(text); - return () => { - handleCleanWordTranslation(); - }; - }, []); - - if (!currentWordTranslation) { + if (!currentWordTranslation || wordTranslationsPendings[text]) { return null; } diff --git a/src/pages/content/components/Subs/Subs.tsx b/src/pages/content/components/Subs/Subs.tsx index 83af918..65dd1b6 100644 --- a/src/pages/content/components/Subs/Subs.tsx +++ b/src/pages/content/components/Subs/Subs.tsx @@ -2,14 +2,17 @@ import { FC, useEffect, useState } from "react"; import { useUnit } from "effector-react"; import Draggable from "react-draggable"; -import { $activePhrasalVerb, $currentSubs, $subsLanguage, activePhrasalVerbChanged } from "@src/models/subs"; +import { $currentSubs } from "@src/models/subs"; import { $video, $wasPaused, wasPausedChanged } from "@src/models/videos"; -import { TPhrasalVerb, TSub, TSubItem } from "@src/models/types"; +import { TSub, TSubItem } from "@src/models/types"; import { $moveBySubsEnabled, $subsBackground, $subsBackgroundOpacity, $subsFontSize } from "@src/models/settings"; -import { $currentSubTranslation, requestSubTranslation, cleanSubTranslation } from "@src/models/translations"; +import { + $findPhrasalVerbsPendings, + subItemMouseEntered, + subItemMouseLeft, + $currentPhrasalVerb, +} from "@src/models/translations"; import { addKeyboardEventsListeners, removeKeyboardEventsListeners } from "@src/utils/keyboardHandler"; -import { findPhrasalVerbs } from "@src/utils/findPhrasalVerbs"; -import { joinTranslations } from "@src/utils/joinTranslations"; import { SubItemTranslation } from "./SubItemTranslation"; import { PhrasalVerbTranslation } from "./PhrasalVerbTranslation"; import { SubFullTranslation } from "./SubFullTranslation"; @@ -70,27 +73,21 @@ export const Subs: FC = () => { const Sub: FC<{ sub: TSub }> = ({ sub }) => { const [showTranslation, setShowTranslation] = useState(false); - const [phrasalVerbs, setPhrasalVerbs] = useState([]); - const [subsBackground, subsBackgroundOpacity, subsLanguage] = useUnit([ + const [subsBackground, subsBackgroundOpacity, findPhrasalVerbsPendings] = useUnit([ $subsBackground, $subsBackgroundOpacity, - $subsLanguage, + $findPhrasalVerbsPendings, ]); - useEffect(() => { - if (subsLanguage === "en") { - setPhrasalVerbs(findPhrasalVerbs(sub.text)); - } - return () => { - setPhrasalVerbs([]); - }; - }, [sub.cleanedText]); - const handleOnClick = (event: React.MouseEvent) => { event.stopPropagation(); setShowTranslation(true); }; + if (findPhrasalVerbsPendings[sub.text]) { + return null; + } + return (
= ({ sub }) => { }} > {sub.items.map((item, index) => ( - + ))} {showTranslation && }
@@ -111,50 +108,53 @@ const Sub: FC<{ sub: TSub }> = ({ sub }) => { type TSubItemProps = { subItem: TSubItem; index: number; - phrasalVerbs: TPhrasalVerb[]; + // phrasalVerbs: TPhrasalVerb[]; }; -const SubItem: FC = ({ subItem, phrasalVerbs, index }) => { - const [activePhrasalVerb, handleActivePhrasalVerbChanged] = useUnit([$activePhrasalVerb, activePhrasalVerbChanged]); +const SubItem: FC = ({ subItem, index }) => { + const [currentPhrasalVerb, handleSubItemMouseEntered, handleSubItemMouseLeft, findPhrasalVerbsPendings] = useUnit([ + $currentPhrasalVerb, + subItemMouseEntered, + subItemMouseLeft, + $findPhrasalVerbsPendings, + ]); const [showTranslation, setShowTranslation] = useState(false); - const [phrasalVerb, setPhrasalVerb] = useState(null); - - useEffect(() => { - setPhrasalVerb(getPhrasalVerb(subItem.cleanedText)); - }, [activePhrasalVerb, phrasalVerbs]); - - const getPhrasalVerb = (word: string): TPhrasalVerb | undefined => { - return phrasalVerbs.find((phrasalVerb) => phrasalVerb.text.includes(word)); - }; const handleOnMouseLeave = () => { setShowTranslation(false); - handleActivePhrasalVerbChanged(null); + handleSubItemMouseLeft(); }; - const handleOnMouseEnter = (phrasalVerb: TPhrasalVerb) => { + const handleOnMouseEnter = () => { setShowTranslation(true); - handleActivePhrasalVerbChanged(phrasalVerb); + handleSubItemMouseEntered(subItem.cleanedText); }; const handleClick = () => { setShowTranslation(false); - handleActivePhrasalVerbChanged(null); + handleSubItemMouseLeft(); }; return ( <>
 handleOnMouseEnter(phrasalVerb)}
+        onMouseEnter={handleOnMouseEnter}
         onMouseLeave={handleOnMouseLeave}
         className={`es-sub-item ${subItem.tag} ${
-          activePhrasalVerb?.indexes?.includes(index) ? "es-sub-item-highlighted" : ""
+          currentPhrasalVerb?.indexes?.includes(index) ? "es-sub-item-highlighted" : ""
         }`}
         onClick={handleClick}
       >
         {subItem.text}
-        {showTranslation && !phrasalVerb && }
-        {showTranslation && phrasalVerb && }
+        {!findPhrasalVerbsPendings[subItem.cleanedText] && showTranslation && (
+          <>
+            {currentPhrasalVerb ? (
+              
+            ) : (
+              
+            )}
+          
+        )}
       
 
diff --git a/src/utils/phrasalVerbs.ts b/src/utils/phrasalVerbs.ts index 1e30158..4cc8831 100644 --- a/src/utils/phrasalVerbs.ts +++ b/src/utils/phrasalVerbs.ts @@ -1661,7 +1661,7 @@ export const PHRASAL_VERBS = { translations: ["выезжать", "брать", "взглянуть на", "взять", "выезжать"], }, "check out of": { - derivatives: ["check out", "checks out", "checking out", "checked out"], + derivatives: ["check out of", "checks out of", "checking out of", "checked out of"], translations: ["выезжать"], }, "check over": {