From cab0ff083ce1f521315028571f9a025d69e2c653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Rialland?= Date: Wed, 9 Aug 2023 19:34:14 +0200 Subject: [PATCH] wip --- site/source/components/App.tsx | 37 ++-- .../ChiffreAffairesActivitéMixte.tsx | 7 +- site/source/components/EngineValue.tsx | 20 +- site/source/components/Notifications.tsx | 5 +- site/source/components/Provider.tsx | 7 +- site/source/components/RuleLink.tsx | 8 +- .../components/SelectSimulationYear.tsx | 8 +- .../ShareSimulationBanner/index.tsx | 10 +- site/source/components/SimulateurWarning.tsx | 8 +- .../components/Simulation/SimulationGoal.tsx | 6 +- site/source/components/StackedBarChart.tsx | 8 +- .../components/conversation/AnswerList.tsx | 16 +- .../components/conversation/Conversation.tsx | 6 +- .../components/conversation/Explicable.tsx | 2 +- .../conversation/MulipleChoicesInput.tsx | 14 +- .../components/conversation/RuleInput.tsx | 9 +- .../conversation/useNavigateQuestions.ts | 5 +- .../source/components/utils/EngineContext.tsx | 12 +- .../utils/useSearchParamsSimulationSharing.ts | 39 ++-- site/source/hooks/useNextQuestion.tsx | 12 +- site/source/pages/_landing/SearchOrCreate.tsx | 17 +- .../AnnuaireEntreprises.tsx | 10 +- site/source/pages/simulateurs/NextSteps.tsx | 8 +- .../store/selectors/simulationSelectors.ts | 5 +- ...ent.tsx => __socialWorkerEngineClient.tsx} | 0 .../worker/socialWorkerEngine.worker.ts | 1 + site/source/worker/workerEngine.ts | 29 +-- site/source/worker/workerEngineClient.ts | 179 ++++++----------- .../source/worker/workerEngineClientReact.tsx | 181 ++++++++++++++++++ 29 files changed, 363 insertions(+), 306 deletions(-) rename site/source/worker/{socialWorkerEngineClient.tsx => __socialWorkerEngineClient.tsx} (100%) create mode 100644 site/source/worker/workerEngineClientReact.tsx diff --git a/site/source/components/App.tsx b/site/source/components/App.tsx index f89979d93..621a52292 100644 --- a/site/source/components/App.tsx +++ b/site/source/components/App.tsx @@ -11,7 +11,7 @@ import { Container } from '@/design-system/layout' import { useAxeCoreAnalysis } from '@/hooks/useAxeCoreAnalysis' import { useGetFullURL } from '@/hooks/useGetFullURL' import { useIsEmbedded } from '@/hooks/useIsEmbedded' -import { useLazyPromise } from '@/hooks/usePromise' +import { useLazyPromise, usePromise } from '@/hooks/usePromise' import { useSaveAndRestoreScrollPosition } from '@/hooks/useSaveAndRestoreScrollPosition' import Landing from '@/pages/_landing/Landing' import Page404 from '@/pages/404' @@ -29,11 +29,9 @@ import { useSitePaths } from '@/sitePaths' import { useAsyncGetRule, useAsyncParsedRules, - useLazyPromiseOnSituationChange, - usePromiseOnSituationChange, useShallowCopy, useWorkerEngine, -} from '@/worker/socialWorkerEngineClient' +} from '@/worker/workerEngineClientReact' import Provider, { ProviderProps } from './Provider' import Redirections from './Redirections' @@ -58,16 +56,16 @@ const TestWorkerEngine = () => { const parsedRules = useAsyncParsedRules() - const resultSmic = usePromiseOnSituationChange( + const resultSmic = usePromise( () => workerEngine.asyncEvaluate('SMIC'), [workerEngine], - { defaultValue: 'loading...' } + 'loading...' ) - const [resultLazySmic, triggerLazySmic] = useLazyPromiseOnSituationChange( + const [resultLazySmic, triggerLazySmic] = useLazyPromise( () => workerEngine.asyncEvaluate('SMIC'), [workerEngine], - { defaultValue: 'wait 2sec...' } + 'wait 2sec...' ) useEffect(() => { @@ -102,24 +100,17 @@ const TestWorkerEngine = () => { workerEngine: workerEngineCopy, }) - const resultSmicCopy = usePromiseOnSituationChange( + const resultSmicCopy = usePromise( async () => workerEngineCopy?.asyncEvaluate('SMIC'), [workerEngineCopy], - { - defaultValue: 'loading...', - workerEngine: workerEngineCopy, - } + 'loading...' ) - const [resultLazySmicCopy, triggerLazySmicCopy] = - useLazyPromiseOnSituationChange( - async () => workerEngineCopy?.asyncEvaluate('SMIC'), - [workerEngineCopy], - { - defaultValue: 'wait 2sec...', - workerEngine: workerEngineCopy, - } - ) + const [resultLazySmicCopy, triggerLazySmicCopy] = useLazyPromise( + async () => workerEngineCopy?.asyncEvaluate('SMIC'), + [workerEngineCopy], + 'wait 2sec...' + ) useEffect(() => { // console.log('useEffect') @@ -133,7 +124,7 @@ const TestWorkerEngine = () => { }, [triggerLazySmicCopy, workerEngine.isWorkerReady]) const { asyncSetSituation } = workerEngineCopy ?? {} - usePromiseOnSituationChange(async () => { + usePromise(async () => { // console.log('**************>', workerEngineCopy, resultSmic) if ( diff --git a/site/source/components/ChiffreAffairesActivitéMixte.tsx b/site/source/components/ChiffreAffairesActivitéMixte.tsx index 526678399..8aa3926cf 100644 --- a/site/source/components/ChiffreAffairesActivitéMixte.tsx +++ b/site/source/components/ChiffreAffairesActivitéMixte.tsx @@ -6,16 +6,15 @@ import { useDispatch, useSelector } from 'react-redux' import { styled } from 'styled-components' import { Switch } from '@/design-system/switch' -import { useLazyPromise } from '@/hooks/usePromise' +import { useLazyPromise, usePromise } from '@/hooks/usePromise' import { batchUpdateSituation } from '@/store/actions/actions' import { situationSelector } from '@/store/selectors/simulationSelectors' import { ReplaceReturnType } from '@/types/utils' import { catchDivideByZeroError } from '@/utils' import { useAsyncGetRule, - usePromiseOnSituationChange, useWorkerEngine, -} from '@/worker/socialWorkerEngineClient' +} from '@/worker/workerEngineClientReact' import { ExplicableRule } from './conversation/Explicable' import { Condition, WhenApplicable } from './EngineValue' @@ -163,7 +162,7 @@ function ActivitéMixte() { const rule = useAsyncGetRule('entreprise . activités . revenus mixtes') const workerEngine = useWorkerEngine() const defaultChecked = - usePromiseOnSituationChange( + usePromise( () => workerEngine.asyncEvaluate('entreprise . activités . revenus mixtes'), [workerEngine] diff --git a/site/source/components/EngineValue.tsx b/site/source/components/EngineValue.tsx index 1fc0cdba3..9a23d6815 100644 --- a/site/source/components/EngineValue.tsx +++ b/site/source/components/EngineValue.tsx @@ -10,11 +10,11 @@ import React from 'react' import { useTranslation } from 'react-i18next' import { keyframes, styled } from 'styled-components' +import { usePromise } from '@/hooks/usePromise' import { useAsyncParsedRules, - usePromiseOnSituationChange, useWorkerEngine, -} from '@/worker/socialWorkerEngineClient' +} from '@/worker/workerEngineClientReact' import RuleLink from './RuleLink' @@ -55,7 +55,7 @@ export default function Value({ const isRule = typeof expression === 'string' && parsedRules && expression in parsedRules - const evaluation = usePromiseOnSituationChange( + const evaluation = usePromise( () => workerEngine.asyncEvaluate({ valeur: expression, @@ -70,7 +70,7 @@ export default function Value({ precision, }) as string - const ruleEvaluation = usePromiseOnSituationChange( + const ruleEvaluation = usePromise( async () => isRule && linkToRule && workerEngine.asyncEvaluate(expression), [expression, isRule, linkToRule, workerEngine] ) @@ -149,7 +149,7 @@ export function Condition({ const workerEngine = useWorkerEngine() - const node = usePromiseOnSituationChange( + const node = usePromise( () => workerEngine.asyncEvaluate({ '!=': [expression, 'non'] }), [expression, workerEngine] ) @@ -175,7 +175,7 @@ export function WhenValueEquals({ // return <>{children} const workerEngine = useWorkerEngine() - const node = usePromiseOnSituationChange( + const node = usePromise( () => workerEngine.asyncEvaluate(expression), [expression, workerEngine] ) @@ -206,7 +206,7 @@ export function WhenApplicable({ // return <>{children} - const node = usePromiseOnSituationChange( + const node = usePromise( () => workerEngine.asyncEvaluate({ 'est applicable': dottedName }), [dottedName, workerEngine] ) @@ -238,7 +238,7 @@ export function WhenNotApplicable({ // return <>{children} const workerEngine = useWorkerEngine() - const node = usePromiseOnSituationChange( + const node = usePromise( () => workerEngine.asyncEvaluate({ 'est non applicable': dottedName }), [dottedName, workerEngine] ) @@ -257,7 +257,7 @@ export function WhenAlreadyDefined({ engineId?: number }) { const workerEngine = useWorkerEngine() - const node = usePromiseOnSituationChange( + const node = usePromise( () => workerEngine.asyncEvaluate({ 'est non défini': dottedName }), [dottedName, workerEngine] ) @@ -275,7 +275,7 @@ export function WhenNotAlreadyDefined({ engineId?: number }) { const workerEngine = useWorkerEngine() - const node = usePromiseOnSituationChange( + const node = usePromise( () => workerEngine.asyncEvaluate({ 'est défini': dottedName }), [dottedName, workerEngine] ) diff --git a/site/source/components/Notifications.tsx b/site/source/components/Notifications.tsx index fd3ebeccf..10f1426ba 100644 --- a/site/source/components/Notifications.tsx +++ b/site/source/components/Notifications.tsx @@ -12,10 +12,7 @@ import { usePromise } from '@/hooks/usePromise' import { hideNotification } from '@/store/actions/actions' import { RootState } from '@/store/reducers/rootReducer' import { isNotNull } from '@/utils' -import { - useWorkerEngine, - WorkerEngine, -} from '@/worker/socialWorkerEngineClient' +import { useWorkerEngine, WorkerEngine } from '@/worker/workerEngineClientReact' import { ExplicableRule } from './conversation/Explicable' import { Appear } from './ui/animate' diff --git a/site/source/components/Provider.tsx b/site/source/components/Provider.tsx index 47bc213de..2250ff21f 100644 --- a/site/source/components/Provider.tsx +++ b/site/source/components/Provider.tsx @@ -20,8 +20,8 @@ import { Body, Intro } from '@/design-system/typography/paragraphs' import { EmbededContextProvider } from '@/hooks/useIsEmbedded' import { Actions } from '@/worker/socialWorkerEngine.worker' import SocialeWorkerEngine from '@/worker/socialWorkerEngine.worker?worker' -import { WorkerEngineProvider } from '@/worker/socialWorkerEngineClient' import { createWorkerEngineClient } from '@/worker/workerEngineClient' +import { WorkerEngineProvider } from '@/worker/workerEngineClientReact' import { Message } from '../design-system' import * as safeLocalStorage from '../storage/safeLocalStorage' @@ -90,10 +90,7 @@ export default function Provider({ - + ( // eslint-disable-next-line react/jsx-props-no-spreading diff --git a/site/source/components/RuleLink.tsx b/site/source/components/RuleLink.tsx index 4f3f9811e..1ac668a89 100644 --- a/site/source/components/RuleLink.tsx +++ b/site/source/components/RuleLink.tsx @@ -3,11 +3,9 @@ import { RuleLink as EngineRuleLink } from 'publicodes-react' import React, { ReactNode } from 'react' import { Link } from '@/design-system/typography/link' +import { usePromise } from '@/hooks/usePromise' import { useSitePaths } from '@/sitePaths' -import { - usePromiseOnSituationChange, - useWorkerEngine, -} from '@/worker/socialWorkerEngineClient' +import { useWorkerEngine } from '@/worker/workerEngineClientReact' // TODO : quicklink -> en cas de variations ou de somme avec un seul élément actif, faire un lien vers cet élément export default function RuleLink( @@ -26,7 +24,7 @@ export default function RuleLink( const [error, setError] = React.useState(false) const workerEngine = useWorkerEngine() - usePromiseOnSituationChange(() => { + usePromise(() => { setLoading(true) setError(false) diff --git a/site/source/components/SelectSimulationYear.tsx b/site/source/components/SelectSimulationYear.tsx index afb7f274b..1a590fb79 100644 --- a/site/source/components/SelectSimulationYear.tsx +++ b/site/source/components/SelectSimulationYear.tsx @@ -5,11 +5,9 @@ import { styled } from 'styled-components' import Banner from '@/components/Banner' import { Link as DesignSystemLink } from '@/design-system/typography/link' +import { usePromise } from '@/hooks/usePromise' import { updateSituation } from '@/store/actions/actions' -import { - usePromiseOnSituationChange, - useWorkerEngine, -} from '@/worker/socialWorkerEngineClient' +import { useWorkerEngine } from '@/worker/workerEngineClientReact' const Bold = styled.span<{ $bold: boolean }>` ${({ $bold }) => ($bold ? 'font-weight: bold;' : '')} @@ -18,7 +16,7 @@ const Bold = styled.span<{ $bold: boolean }>` export const SelectSimulationYear = () => { const dispatch = useDispatch() const workerEngine = useWorkerEngine() - const year = usePromiseOnSituationChange( + const year = usePromise( () => workerEngine.asyncEvaluate('date'), [workerEngine] ) diff --git a/site/source/components/ShareSimulationBanner/index.tsx b/site/source/components/ShareSimulationBanner/index.tsx index e91dc1961..a9ed133a3 100644 --- a/site/source/components/ShareSimulationBanner/index.tsx +++ b/site/source/components/ShareSimulationBanner/index.tsx @@ -8,10 +8,6 @@ import { Button } from '@/design-system/buttons' import { Emoji } from '@/design-system/emoji' import { Grid, Spacing } from '@/design-system/layout' import { useCurrentSimulatorData } from '@/hooks/useCurrentSimulatorData' -import { - companySituationSelector, - situationSelector, -} from '@/store/selectors/simulationSelectors' import { TrackingContext } from '../ATInternetTracking' import { PlaceDesEntreprisesButton } from '../PlaceDesEntreprises' @@ -20,12 +16,8 @@ import { ShareSimulationPopup } from './ShareSimulationPopup' export function useUrl() { const language = useTranslation().i18n.language - const situation = { - ...useSelector(situationSelector), - ...useSelector(companySituationSelector), - } - const searchParams = useParamsFromSituation(situation) + const searchParams = useParamsFromSituation() const { currentSimulatorData } = useCurrentSimulatorData() const { path = '' } = currentSimulatorData ?? {} diff --git a/site/source/components/SimulateurWarning.tsx b/site/source/components/SimulateurWarning.tsx index 87c299465..b93c6f16f 100644 --- a/site/source/components/SimulateurWarning.tsx +++ b/site/source/components/SimulateurWarning.tsx @@ -6,11 +6,9 @@ import Warning from '@/components/ui/WarningBlock' import { Link } from '@/design-system/typography/link' import { Li, Ul } from '@/design-system/typography/list' import { Body } from '@/design-system/typography/paragraphs' +import { usePromise } from '@/hooks/usePromise' import { AbsoluteSitePaths } from '@/sitePaths' -import { - usePromiseOnSituationChange, - useWorkerEngine, -} from '@/worker/socialWorkerEngineClient' +import { useWorkerEngine } from '@/worker/workerEngineClientReact' type SimulateurWarningProps = { simulateur: Exclude @@ -20,7 +18,7 @@ export default function SimulateurWarning({ simulateur, }: SimulateurWarningProps) { const workerEngine = useWorkerEngine() - const year = usePromiseOnSituationChange( + const year = usePromise( () => workerEngine.asyncEvaluate('date'), [workerEngine] ) diff --git a/site/source/components/Simulation/SimulationGoal.tsx b/site/source/components/Simulation/SimulationGoal.tsx index 63608df69..da579ce37 100644 --- a/site/source/components/Simulation/SimulationGoal.tsx +++ b/site/source/components/Simulation/SimulationGoal.tsx @@ -8,13 +8,13 @@ import { ForceThemeProvider } from '@/components/utils/DarkModeContext' import { Grid } from '@/design-system/layout' import { Strong } from '@/design-system/typography' import { Body, SmallBody } from '@/design-system/typography/paragraphs' +import { usePromise } from '@/hooks/usePromise' import { updateSituation } from '@/store/actions/actions' import { targetUnitSelector } from '@/store/selectors/simulationSelectors' import { useAsyncGetRule, - usePromiseOnSituationChange, useWorkerEngine, -} from '@/worker/socialWorkerEngineClient' +} from '@/worker/workerEngineClientReact' import { ExplicableRule } from '../conversation/Explicable' import RuleInput, { InputProps } from '../conversation/RuleInput' @@ -54,7 +54,7 @@ export function SimulationGoal({ const dispatch = useDispatch() const currentUnit = useSelector(targetUnitSelector) const workerEngine = useWorkerEngine() - const evaluation = usePromiseOnSituationChange( + const evaluation = usePromise( () => workerEngine.asyncEvaluate({ value: dottedName, diff --git a/site/source/components/StackedBarChart.tsx b/site/source/components/StackedBarChart.tsx index 0012add32..da9abfea8 100755 --- a/site/source/components/StackedBarChart.tsx +++ b/site/source/components/StackedBarChart.tsx @@ -8,11 +8,9 @@ import { styled } from 'styled-components' import RuleLink from '@/components/RuleLink' import useDisplayOnIntersecting from '@/components/utils/useDisplayOnIntersecting' +import { usePromise } from '@/hooks/usePromise' import { targetUnitSelector } from '@/store/selectors/simulationSelectors' -import { - usePromiseOnSituationChange, - useWorkerEngine, -} from '@/worker/socialWorkerEngineClient' +import { useWorkerEngine } from '@/worker/workerEngineClientReact' import { DisableAnimationContext } from './utils/DisableAnimationContext' @@ -208,7 +206,7 @@ export default function StackedRulesChart({ const targetUnit = useSelector(targetUnitSelector) const workerEngine = useWorkerEngine() - const datas = usePromiseOnSituationChange( + const datas = usePromise( () => Promise.all( data.map(async ({ dottedName, title, color }) => ({ diff --git a/site/source/components/conversation/AnswerList.tsx b/site/source/components/conversation/AnswerList.tsx index 1f2c21017..070ab8878 100644 --- a/site/source/components/conversation/AnswerList.tsx +++ b/site/source/components/conversation/AnswerList.tsx @@ -1,16 +1,10 @@ import { DottedName } from 'modele-social' -import { - EvaluatedNode, - PublicodesExpression, - RuleNode, - utils, -} from 'publicodes' +import { PublicodesExpression, RuleNode, utils } from 'publicodes' import { useCallback, useMemo } from 'react' import { Trans, useTranslation } from 'react-i18next' import { useDispatch, useSelector } from 'react-redux' import { styled } from 'styled-components' -import { EvaluatedRule } from '@/components/utils/EngineContext' import { Message, PopoverWithTrigger } from '@/design-system' import { Button } from '@/design-system/buttons' import { Emoji } from '@/design-system/emoji' @@ -31,7 +25,7 @@ import { companySituationSelector, situationSelector, } from '@/store/selectors/simulationSelectors' -import { useWorkerEngine } from '@/worker/socialWorkerEngineClient' +import { useWorkerEngine } from '@/worker/workerEngineClientReact' import Value from '../EngineValue' import { JeDonneMonAvis } from '../JeDonneMonAvis' @@ -77,11 +71,11 @@ export default function AnswerList({ onClose, children }: AnswerListProps) { async (dottedName) => workerEngine.asyncEvaluate( await workerEngine.asyncGetRule(dottedName) - ) as Promise + ) as Promise> ) ), [nextQuestions, workerEngine], - [] as EvaluatedRule[] + [] as RuleNode[] ) const situationQuestions = useMemo( @@ -272,7 +266,7 @@ export default function AnswerList({ onClose, children }: AnswerListProps) { function StepsTable({ rules, }: { - rules: Array + rules: Array onClose: () => void }) { const { t } = useTranslation() diff --git a/site/source/components/conversation/Conversation.tsx b/site/source/components/conversation/Conversation.tsx index 9cb5d1c75..e7f8e7c16 100644 --- a/site/source/components/conversation/Conversation.tsx +++ b/site/source/components/conversation/Conversation.tsx @@ -13,6 +13,7 @@ import { Grid, Spacing } from '@/design-system/layout' import { H3 } from '@/design-system/typography/heading' import { Body } from '@/design-system/typography/paragraphs' import { useCurrentSimulatorData } from '@/hooks/useCurrentSimulatorData' +import { usePromise } from '@/hooks/usePromise' import { answerQuestion } from '@/store/actions/actions' import { answeredQuestionsSelector, @@ -20,10 +21,9 @@ import { } from '@/store/selectors/simulationSelectors' import { useAsyncGetRule, - usePromiseOnSituationChange, useWorkerEngine, WorkerEngine, -} from '@/worker/socialWorkerEngineClient' +} from '@/worker/workerEngineClientReact' import { TrackPage } from '../ATInternetTracking' import { JeDonneMonAvis } from '../JeDonneMonAvis' @@ -94,7 +94,7 @@ export default function Conversation({ const workerEngine = useWorkerEngine() const rule = useAsyncGetRule(currentQuestion) - const question = usePromiseOnSituationChange( + const question = usePromise( async () => rule && evaluateQuestion(workerEngine, rule), [rule, workerEngine] ) diff --git a/site/source/components/conversation/Explicable.tsx b/site/source/components/conversation/Explicable.tsx index a3da09ff1..a16d33d3f 100644 --- a/site/source/components/conversation/Explicable.tsx +++ b/site/source/components/conversation/Explicable.tsx @@ -7,7 +7,7 @@ import HelpButtonWithPopover from '@/design-system/buttons/HelpButtonWithPopover import { Spacing } from '@/design-system/layout' import { H3 } from '@/design-system/typography/heading' import { usePromise } from '@/hooks/usePromise' -import { useWorkerEngine } from '@/worker/socialWorkerEngineClient' +import { useWorkerEngine } from '@/worker/workerEngineClientReact' import { References } from '../References' import RuleLink from '../RuleLink' diff --git a/site/source/components/conversation/MulipleChoicesInput.tsx b/site/source/components/conversation/MulipleChoicesInput.tsx index 476a64a4b..bbba95311 100644 --- a/site/source/components/conversation/MulipleChoicesInput.tsx +++ b/site/source/components/conversation/MulipleChoicesInput.tsx @@ -6,11 +6,7 @@ import { useTranslation } from 'react-i18next' import { Checkbox } from '@/design-system' import { Emoji } from '@/design-system/emoji' import { usePromise } from '@/hooks/usePromise' -import { - usePromiseOnSituationChange, - useWorkerEngine, - WorkerEngine, -} from '@/worker/socialWorkerEngineClient' +import { useWorkerEngine, WorkerEngine } from '@/worker/workerEngineClientReact' import { ExplicableRule } from './Explicable' import { InputProps, RuleWithMultiplePossibilities } from './RuleInput' @@ -67,19 +63,19 @@ type CheckBoxRuleProps = { function CheckBoxRule({ node, engineId, onChange }: CheckBoxRuleProps) { const workerEngine = useWorkerEngine() - const evaluation = usePromiseOnSituationChange( + const evaluation = usePromise( () => workerEngine.asyncEvaluate(node), - [engineId, node, workerEngine] + [node, workerEngine] ) const { t } = useTranslation() - if (evaluation.nodeValue === null) { + if (evaluation?.nodeValue === null) { return null } return ( <> onChange(isSelected)} diff --git a/site/source/components/conversation/RuleInput.tsx b/site/source/components/conversation/RuleInput.tsx index 89dfa3969..60cc3d9f4 100644 --- a/site/source/components/conversation/RuleInput.tsx +++ b/site/source/components/conversation/RuleInput.tsx @@ -16,10 +16,9 @@ import { usePromise } from '@/hooks/usePromise' import { getMeta, isNotNull } from '@/utils' import { useAsyncGetRule, - usePromiseOnSituationChange, useWorkerEngine, WorkerEngine, -} from '@/worker/socialWorkerEngineClient' +} from '@/worker/workerEngineClientReact' import { Choice, MultipleAnswerInput, OuiNonInput } from './ChoicesInput' import DateInput from './DateInput' @@ -107,7 +106,7 @@ export default function RuleInput({ // const evaluation = engineValue.evaluate({ valeur: dottedName, ...modifiers }) // async - const evaluation = usePromiseOnSituationChange( + const evaluation = usePromise( () => workerEngine.asyncEvaluate({ valeur: dottedName, @@ -118,7 +117,7 @@ export default function RuleInput({ const value = evaluation?.nodeValue - const isMultipleChoices = usePromiseOnSituationChange( + const isMultipleChoices = usePromise( async () => rule && isMultiplePossibilities(workerEngine, engineId, dottedName), [dottedName, engineId, rule, workerEngine] @@ -128,7 +127,7 @@ export default function RuleInput({ const choice = usePromise( () => getOnePossibilityOptions(workerEngine, dottedName), - [workerEngine.situationVersion, dottedName] + [workerEngine, dottedName] ) dottedName === 'entreprise . activité . nature' && diff --git a/site/source/components/conversation/useNavigateQuestions.ts b/site/source/components/conversation/useNavigateQuestions.ts index 4a2412b80..775bc2119 100644 --- a/site/source/components/conversation/useNavigateQuestions.ts +++ b/site/source/components/conversation/useNavigateQuestions.ts @@ -12,10 +12,7 @@ import { currentQuestionSelector, useMissingVariables, } from '@/store/selectors/simulationSelectors' -import { - useWorkerEngine, - WorkerEngine, -} from '@/worker/socialWorkerEngineClient' +import { useWorkerEngine, WorkerEngine } from '@/worker/workerEngineClientReact' export function useNavigateQuestions(workerEngines?: WorkerEngine[]) { const dispatch = useDispatch() diff --git a/site/source/components/utils/EngineContext.tsx b/site/source/components/utils/EngineContext.tsx index 7f0416f3b..1d3d51900 100644 --- a/site/source/components/utils/EngineContext.tsx +++ b/site/source/components/utils/EngineContext.tsx @@ -16,10 +16,7 @@ import { situationSelector, } from '@/store/selectors/simulationSelectors' import { omit } from '@/utils' -import { - useWorkerEngine, - WorkerEngine, -} from '@/worker/socialWorkerEngineClient' +import { useWorkerEngine, WorkerEngine } from '@/worker/workerEngineClientReact' import i18n from '../../locales/i18n' @@ -203,10 +200,3 @@ export const useSetupSafeSituation = (workerEngine?: WorkerEngine) => { // engine.setSituation() // } } - -// export function useInversionFail() { -// return useContext(EngineContext).inversionFail() -// } - -export type EvaluatedRule = EvaluatedNode & - RuleNode & { dottedName: DottedName } diff --git a/site/source/components/utils/useSearchParamsSimulationSharing.ts b/site/source/components/utils/useSearchParamsSimulationSharing.ts index a5bb4a486..c484d33e5 100644 --- a/site/source/components/utils/useSearchParamsSimulationSharing.ts +++ b/site/source/components/utils/useSearchParamsSimulationSharing.ts @@ -4,16 +4,20 @@ import { useEffect, useMemo, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useSearchParams } from 'react-router-dom' +import { usePromise } from '@/hooks/usePromise' // import { useEngine } from '@/components/utils/EngineContext' import { batchUpdateSituation, setActiveTarget } from '@/store/actions/actions' import { Situation } from '@/store/reducers/rootReducer' -import { configObjectifsSelector } from '@/store/selectors/simulationSelectors' +import { + companySituationSelector, + configObjectifsSelector, + situationSelector, +} from '@/store/selectors/simulationSelectors' import { useAsyncParsedRules, - usePromiseOnSituationChange, useWorkerEngine, WorkerEngine, -} from '@/worker/socialWorkerEngineClient' +} from '@/worker/workerEngineClientReact' type ShortName = string // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents @@ -69,24 +73,23 @@ export default function useSearchParamsSimulationSharing() { }, []) } -export const useParamsFromSituation = (situation: Situation) => { +export const useParamsFromSituation = () => { + const situation = useSelector(situationSelector) + const companySituation = useSelector(companySituationSelector) const parsedRules = useAsyncParsedRules() const workerEngine = useWorkerEngine() - const dottedNameParamName = useMemo( - () => (parsedRules ? getRulesParamNames(parsedRules) : []), - [parsedRules] - ) - const ret = usePromiseOnSituationChange( - () => - getSearchParamsFromSituation( - workerEngine, - situation, - dottedNameParamName - ), - // eslint-disable-next-line react-hooks/exhaustive-deps - [dottedNameParamName, workerEngine] - ) + const ret = usePromise(() => { + const dottedNameParamName = parsedRules + ? getRulesParamNames(parsedRules) + : [] + + return getSearchParamsFromSituation( + workerEngine, + { ...situation, ...companySituation }, + dottedNameParamName + ) + }, [companySituation, parsedRules, situation, workerEngine]) return ret } diff --git a/site/source/hooks/useNextQuestion.tsx b/site/source/hooks/useNextQuestion.tsx index 778ea3e4b..cc5f96bcd 100644 --- a/site/source/hooks/useNextQuestion.tsx +++ b/site/source/hooks/useNextQuestion.tsx @@ -10,11 +10,9 @@ import { useMissingVariables, } from '@/store/selectors/simulationSelectors' import { ImmutableType } from '@/types/utils' -import { - usePromiseOnSituationChange, - useWorkerEngine, - WorkerEngine, -} from '@/worker/socialWorkerEngineClient' +import { useWorkerEngine, WorkerEngine } from '@/worker/workerEngineClientReact' + +import { usePromise } from './usePromise' // import { useEngine } from '../components/utils/EngineContext' @@ -79,7 +77,7 @@ export const useNextQuestions = function ( const workerEngine = useWorkerEngine() const missingVariables = useMissingVariables(workerEngines) - const nextQuestions = usePromiseOnSituationChange( + const nextQuestions = usePromise( async () => { const next = getNextQuestions( missingVariables, @@ -94,7 +92,7 @@ export const useNextQuestions = function ( return next.filter((_, i) => rules[i].rawNode.question !== undefined) }, [missingVariables, config.questions, answeredQuestions, workerEngine], - { defaultValue: [] as DottedName[] } + [] as DottedName[] ) return nextQuestions diff --git a/site/source/pages/_landing/SearchOrCreate.tsx b/site/source/pages/_landing/SearchOrCreate.tsx index e0d452991..907228aa1 100644 --- a/site/source/pages/_landing/SearchOrCreate.tsx +++ b/site/source/pages/_landing/SearchOrCreate.tsx @@ -17,11 +17,12 @@ import { Grid, Spacing } from '@/design-system/layout' import PopoverConfirm from '@/design-system/popover/PopoverConfirm' import { H3 } from '@/design-system/typography/heading' import { Body } from '@/design-system/typography/paragraphs' +import { usePromise } from '@/hooks/usePromise' import { useSetEntreprise } from '@/hooks/useSetEntreprise' import { useSitePaths } from '@/sitePaths' import { getCookieValue } from '@/storage/readCookie' import { resetCompany } from '@/store/actions/companyActions' -import { usePromiseOnSituationChange } from '@/worker/socialWorkerEngineClient' +import { useWorkerEngine } from '@/worker/workerEngineClientReact' // import { RootState } from '@/store/reducers/rootReducer' @@ -30,9 +31,10 @@ export default function SearchOrCreate() { // const statutChoisi = useSelector( // (state: RootState) => state.choixStatutJuridique.companyStatusChoice // ) - const companySIREN = usePromiseOnSituationChange( - () => asyncEvaluate('entreprise . SIREN'), - [] + const workerEngine = useWorkerEngine() + const companySIREN = usePromise( + () => workerEngine.asyncEvaluate('entreprise . SIREN'), + [workerEngine] )?.nodeValue useSetEntrepriseFromUrssafConnection() const handleCompanySubmit = useHandleCompanySubmit() @@ -169,9 +171,10 @@ function useHandleCompanySubmit() { function useSetEntrepriseFromUrssafConnection() { const setEntreprise = useSetEntreprise() const siret = siretFromUrssafFrConnection() - const companySIREN = usePromiseOnSituationChange( - () => asyncEvaluate('entreprise . SIREN'), - [] + const workerEngine = useWorkerEngine() + const companySIREN = usePromise( + () => workerEngine.asyncEvaluate('entreprise . SIREN'), + [workerEngine] )?.nodeValue useEffect(() => { diff --git a/site/source/pages/assistants/pour-mon-entreprise/AnnuaireEntreprises.tsx b/site/source/pages/assistants/pour-mon-entreprise/AnnuaireEntreprises.tsx index ca0b47a7f..5c73bf781 100644 --- a/site/source/pages/assistants/pour-mon-entreprise/AnnuaireEntreprises.tsx +++ b/site/source/pages/assistants/pour-mon-entreprise/AnnuaireEntreprises.tsx @@ -1,19 +1,17 @@ import { useTranslation } from 'react-i18next' import { Article } from '@/design-system/card' -import { - usePromiseOnSituationChange, - useWorkerEngine, -} from '@/worker/socialWorkerEngineClient' +import { usePromise } from '@/hooks/usePromise' +import { useWorkerEngine } from '@/worker/workerEngineClientReact' export function AnnuaireEntreprises() { const { t } = useTranslation() const workerEngine = useWorkerEngine() - const siren = usePromiseOnSituationChange( + const siren = usePromise( async () => await workerEngine.asyncEvaluate('entreprise . SIREN'), [workerEngine], - { defaultValue: null } + null )?.nodeValue as string | null return typeof siren === 'string' ? ( diff --git a/site/source/pages/simulateurs/NextSteps.tsx b/site/source/pages/simulateurs/NextSteps.tsx index b4225fe4c..ea43655ef 100644 --- a/site/source/pages/simulateurs/NextSteps.tsx +++ b/site/source/pages/simulateurs/NextSteps.tsx @@ -7,13 +7,11 @@ import { MergedSimulatorDataValues, useCurrentSimulatorData, } from '@/hooks/useCurrentSimulatorData' +import { usePromise } from '@/hooks/usePromise' import { GuideURSSAFCard } from '@/pages/simulateurs/cards/GuideURSSAFCard' import { IframeIntegrationCard } from '@/pages/simulateurs/cards/IframeIntegrationCard' import { useSitePaths } from '@/sitePaths' -import { - usePromiseOnSituationChange, - useWorkerEngine, -} from '@/worker/socialWorkerEngineClient' +import { useWorkerEngine } from '@/worker/workerEngineClientReact' import { AnnuaireEntreprises } from '../assistants/pour-mon-entreprise/AnnuaireEntreprises' import { AutoEntrepreneurCard } from '../assistants/pour-mon-entreprise/AutoEntrepeneurCard' @@ -31,7 +29,7 @@ export function NextSteps({ iframePath, nextSteps }: NextStepsProps) { const workerEngine = useWorkerEngine() const { key } = useCurrentSimulatorData() - const guideUrssaf = usePromiseOnSituationChange( + const guideUrssaf = usePromise( async () => ( await Promise.all( diff --git a/site/source/store/selectors/simulationSelectors.ts b/site/source/store/selectors/simulationSelectors.ts index 25b74c69f..929b540b3 100644 --- a/site/source/store/selectors/simulationSelectors.ts +++ b/site/source/store/selectors/simulationSelectors.ts @@ -6,10 +6,7 @@ import { createSelector } from 'reselect' import { usePromise } from '@/hooks/usePromise' // import { useEngine } from '@/components/utils/EngineContext' import { RootState, Situation } from '@/store/reducers/rootReducer' -import { - useWorkerEngine, - WorkerEngine, -} from '@/worker/socialWorkerEngineClient' +import { useWorkerEngine, WorkerEngine } from '@/worker/workerEngineClientReact' export const configSelector = (state: RootState) => state.simulation?.config ?? {} diff --git a/site/source/worker/socialWorkerEngineClient.tsx b/site/source/worker/__socialWorkerEngineClient.tsx similarity index 100% rename from site/source/worker/socialWorkerEngineClient.tsx rename to site/source/worker/__socialWorkerEngineClient.tsx diff --git a/site/source/worker/socialWorkerEngine.worker.ts b/site/source/worker/socialWorkerEngine.worker.ts index 74841bd9a..5868da5fc 100644 --- a/site/source/worker/socialWorkerEngine.worker.ts +++ b/site/source/worker/socialWorkerEngine.worker.ts @@ -44,6 +44,7 @@ const logger = { const init = ({ basename }: Pick) => { let rules = rawRules + if (basename === 'infrance') { // eslint-disable-next-line @typescript-eslint/no-unsafe-argument rules = translateRules('en', ruleTranslations, rules) diff --git a/site/source/worker/workerEngine.ts b/site/source/worker/workerEngine.ts index 340183bf9..fbdb8a70b 100644 --- a/site/source/worker/workerEngine.ts +++ b/site/source/worker/workerEngine.ts @@ -5,8 +5,8 @@ import Engine from 'publicodes' */ export type WorkerEngineActions< - InitParams extends unknown[], - Name extends string, + InitParams extends unknown[] = unknown[], + Name extends string = string, > = | { action: 'init' @@ -44,9 +44,10 @@ export type WorkerEngineActions< result: void } -type DistributiveOmit = T extends unknown - ? Omit - : never +export type WorkerEngineAction< + Actions extends WorkerEngineActions, + Action extends Actions['action'], +> = Extract type GenericParams = { /** @@ -60,24 +61,24 @@ type GenericParams = { id: number } -export type WorkerEngineAction< - Acts extends WorkerEngineActions, - T extends Acts['action'], -> = Extract +type DistributiveOmit = T extends unknown + ? Omit + : never +/** + */ export const createWorkerEngine = < - Name extends string, - EngineType extends Engine, + Name extends string = string, InitParams extends unknown[] = unknown[], >( - init: (...params: InitParams) => EngineType + init: (...params: InitParams) => Engine ) => { type Params = DistributiveOmit< WorkerEngineActions & GenericParams, 'result' > - let engines: (EngineType | undefined)[] = [] + let engines: (Engine | undefined)[] = [] let queue: (Params & { engineId: number })[] = [] let setDefaultEngineReady: (() => void) | null = null @@ -121,7 +122,7 @@ export const createWorkerEngine = < return { id, result } } else if (action === 'shallowCopy') { - engines.push(engine.shallowCopy() as EngineType) + engines.push(engine.shallowCopy()) return { id, result: engines.length - 1 } } else if (action === 'deleteShallowCopy') { diff --git a/site/source/worker/workerEngineClient.ts b/site/source/worker/workerEngineClient.ts index a764e3a5b..b0aa619cf 100644 --- a/site/source/worker/workerEngineClient.ts +++ b/site/source/worker/workerEngineClient.ts @@ -18,21 +18,25 @@ const isBatch = (val: object): val is { batch: unknown[] } => 'batch' in val && Array.isArray(val.batch) interface WorkerEnginePromise< - Actions extends WorkerEngineActions, - InitParams extends unknown[] = unknown[], - Name extends string = string, - T extends Actions['action'] = Actions['action'], + Actions extends WorkerEngineActions = WorkerEngineActions, + ActionNames extends Actions['action'] = Actions['action'], + // InitParams extends unknown[] = unknown[], + // Name extends string = string, + // T extends Actions['action'] = Actions['action'], > { engineId: number - action: T + action: ActionNames resolve: (value: unknown) => void reject: (value: unknown) => void } interface Ctx< - Actions extends WorkerEngineActions, - InitParams extends unknown[] = unknown[], - Name extends string = string, + Actions extends WorkerEngineActions = WorkerEngineActions, + // Promises extends WorkerEnginePromise = WorkerEnginePromise, + // > + // Actions extends WorkerEngineActions, + // InitParams extends unknown[] = unknown[], + // Name extends string = string, > { engineId: number promises: WorkerEnginePromise[] @@ -41,17 +45,10 @@ interface Ctx< isWorkerReady: Promise } -export type WorkerEngineClient< - Actions extends WorkerEngineActions, - InitParams extends unknown[] = unknown[], - Name extends string = string, -> = ReturnType> +export type WorkerEngineClient = + ReturnType> -export const createWorkerEngineClient = < - Actions extends WorkerEngineActions, - InitParams extends unknown[] = unknown[], - Name extends string = string, ->( +export const createWorkerEngineClient = ( worker: Worker, options: { initParams: WorkerEngineAction['params'] @@ -116,53 +113,30 @@ export const createWorkerEngineClient = < const workerEngine = workerEngineConstruct(ctx, { onSituationChange }) - void postMessage(ctx, 'setSituation') - return workerEngine } -// type ActionType< -// Actions extends WorkerEngineActions, -// ActionNames extends Actions['action'], -// InitParams extends unknown[] = unknown[], -// Name extends string = string, -// > = WorkerEngineAction - -// type Action = WorkerEngineAction - -// const postMessage = async >( -// engineId: number, -// action: T, -// ...params: U['params'] -// // ...params: U['params'] extends [] ? [] : U['params'] -// ) => { - +/** + * Post message to worker engine and return a promise to get the result, + * if the promise is not resolved in 10 seconds, it will be rejected. + * @param ctx + * @param action + * @param params + */ const postMessage = async < - Actions extends WorkerEngineActions, - Action extends WorkerEngineAction, + Actions extends WorkerEngineActions, ActionNames extends Actions['action'], - InitParams extends unknown[] = unknown[], - Name extends string = string, + Action extends WorkerEngineAction, >( - // ActionNames extends Actions['action'], - // Actions extends WorkerEngineActions, - // InitParams extends unknown[] = unknown[], - // Name extends string = string, - - // Action extends Actions['action'], - // Actions extends WorkerEngineActions, - // InitParams extends unknown[] = unknown[], - // Name extends string = string, - ctx: Ctx, + ctx: Ctx, action: ActionNames, ...params: Action['params'] - // ...params: U['params'] extends [] ? [] : U['params'] ) => { const { engineId, worker } = ctx console.log('{postMessage}', action, params) - const promiseTimeout = 100000 + const promiseTimeout = 10000 const warning = setTimeout(() => { console.log('{promise waiting for too long, aborting!}', action, params) ctx.promises[id].reject?.(new Error('timeout')) @@ -208,65 +182,29 @@ const postMessage = async < return promise } -const workerEngineConstruct = < - // ActionNames extends Actions['action'], - Actions extends WorkerEngineActions, - InitParams extends unknown[] = unknown[], - Name extends string = string, ->( +/** + */ +const wrappedPostMessage = + (ctx: Ctx) => + < + Actions extends WorkerEngineActions, + ActionNames extends Actions['action'], + Action extends WorkerEngineAction, + >( + action: ActionNames, + ...params: Action['params'] + ) => + postMessage(ctx, action, ...params) + +/** + */ +const workerEngineConstruct = ( ctx: Ctx, options: { - // engineId: number - // worker: Worker - // isWorkerReady: Promise['result']> onSituationChange?: (engineId: number) => void - // postMessage: < - // T extends Actions['action'], - // U extends Extract, - // >( - // engineId: number, - // action: T, - // ...params: U['params'] - // ) => Promise } ) => { - type Act = WorkerEngineAction - - // const yyyy = < - // ActionNames extends Actions['action'], - // Act extends Action, - // Actions extends WorkerEngineActions, - // InitParams extends unknown[] = unknown[], - // Name extends string = string, - // >( - // action: ActionNames, - // ...params: Act['params'] - // ) => postMessage(ctx, action, ...params) - - // interface PostMessage { - // < - // ActionNames extends Actions['action'], - // Act extends Action, - // >( - // action: ActionNames, - // ...params: Act['params'] - // ): Promise - // } - - const wrappedPostMessage = - (ctx: Ctx) => - < - ActionNames extends Actions['action'], - Action extends WorkerEngineAction, - >( - action: ActionNames, - ...params: Action['params'] - ) => - postMessage(ctx, action, ...params) - - // await postMessage(ctx, '') - // await wrappedPostMessage(ctx)('') - // await wrappedPostMessage(ctx)('') + type Action = WorkerEngineAction const context = { engineId: ctx.engineId, @@ -285,15 +223,8 @@ const workerEngineConstruct = < * This function is used to set the situation in the worker with a specific engineId. */ asyncSetSituation: async ( - ...params: Act<'setSituation'>['params'] - ): Promise['result']> => { - // abort every action "evaluate" - // promises.forEach((promise) => { - // if (engineId === promise.engineId && promise.action === 'evaluate') { - // promise.reject?.('abort') - // } - // }) - + ...params: Action<'setSituation'>['params'] + ): Promise['result']> => { const ret = await context.postMessage('setSituation', ...params) context.onSituationChange?.(ctx.engineId) @@ -305,8 +236,8 @@ const workerEngineConstruct = < * This function is used to evaluate a publicodes expression in the worker with a specific engineId. */ asyncEvaluate: async ( - ...params: Act<'evaluate'>['params'] - ): Promise['result']> => { + ...params: Action<'evaluate'>['params'] + ): Promise['result']> => { const promise = await context.postMessage('evaluate', ...params) // console.trace('{asyncEvaluate}') @@ -318,15 +249,17 @@ const workerEngineConstruct = < * This function is used to get a publicodes rule that is in the worker with a specific EngineId. */ asyncGetRule: async ( - ...params: Act<'getRule'>['params'] - ): Promise['result']> => { + ...params: Action<'getRule'>['params'] + ): Promise['result']> => { return await context.postMessage('getRule', ...params) }, /** * This function is used to get all the parsed rules in the worker with a specific engineId. */ - asyncGetParsedRules: async (): Promise['result']> => { + asyncGetParsedRules: async (): Promise< + Action<'getParsedRules'>['result'] + > => { return await context.postMessage('getParsedRules') }, @@ -334,16 +267,16 @@ const workerEngineConstruct = < * This function is used to shallow copy an engine in the worker with a specific engineId. */ asyncShallowCopy: async (onSituationChange: () => void = () => {}) => { - const newEngineId = await context.postMessage('shallowCopy') + const engineId = await context.postMessage('shallowCopy') - return workerEngineConstruct(ctx, { onSituationChange }) + return workerEngineConstruct({ ...ctx, engineId }, { onSituationChange }) }, /** * This function is used to delete a shallow copy of an engine in the worker. */ asyncDeleteShallowCopy: async (): Promise< - Act<'deleteShallowCopy'>['result'] + Action<'deleteShallowCopy'>['result'] > => { return context.postMessage('deleteShallowCopy') }, diff --git a/site/source/worker/workerEngineClientReact.tsx b/site/source/worker/workerEngineClientReact.tsx new file mode 100644 index 000000000..968b2ffe8 --- /dev/null +++ b/site/source/worker/workerEngineClientReact.tsx @@ -0,0 +1,181 @@ +import { DottedName } from 'modele-social' +import { + createContext, + useContext, + useEffect, + useMemo, + useState, + useTransition, +} from 'react' + +import { useSetupSafeSituation } from '@/components/utils/EngineContext' +import { usePromise } from '@/hooks/usePromise' + +import { Actions } from './socialWorkerEngine.worker' +import { WorkerEngineClient } from './workerEngineClient' + +/** + */ +export const useSynchronizedWorkerEngine = ( + workerClient: WorkerEngineClient +) => { + const [transition, startTransition] = useTransition() + + const [situationVersion, setSituationVersion] = useState(0) + const [workerEngine, setWorkerEngine] = useState>( + () => { + workerClient.onSituationChange = function () { + console.log('onSituationChange', workerClient.engineId) + + startTransition(() => { + setSituationVersion((situationVersion) => { + return situationVersion + 1 + }) + }) + } + + return workerClient + } + ) + + const memo = useMemo(() => { + return { ...workerEngine, situationVersion } + }, [situationVersion, workerEngine]) + + return memo +} + +export type WorkerEngine = NonNullable< + ReturnType +> + +const WorkerEngineContext = createContext( + undefined as unknown as WorkerEngine +) + +/** + */ +export const useWorkerEngine = () => { + const context = useContext(WorkerEngineContext) + + if (!context && !import.meta.env.SSR) { + throw new Error( + 'You are trying to use the worker engine outside of its provider' + ) + } + + return context +} + +/** + */ +export const WorkerEngineProvider = ({ + workerClient, + children, +}: { + workerClient: WorkerEngineClient + children: React.ReactNode +}) => { + const workerEngine = useSynchronizedWorkerEngine(workerClient) + + useSetupSafeSituation(workerEngine) + + if (workerEngine === undefined) { + return children + } + + return ( + + {children} + + ) +} + +interface Options { + workerEngine?: WorkerEngine + defaultValue?: DefaultValue +} + +/** + * This hook is used to get a rule in the worker engine. + */ +export const useAsyncGetRule = < + DefaultValue = undefined, // +>( + dottedName: DottedName, + { defaultValue, workerEngine: workerEngineOption }: Options = {} +) => { + const defaultWorkerEngine = useWorkerEngine() + const workerEngine = workerEngineOption ?? defaultWorkerEngine + + return usePromise( + async () => workerEngine.asyncGetRule(dottedName), + [dottedName, workerEngine], + defaultValue + ) +} + +/** + * This hook is used to get parsed rules in the worker engine. + */ +export const useAsyncParsedRules = < + DefaultValue = undefined, // +>({ + workerEngine: workerEngineOption, + defaultValue, +}: Options = {}) => { + const defaultWorkerEngine = useWorkerEngine() + const workerEngine = workerEngineOption ?? defaultWorkerEngine + + return usePromise( + async () => workerEngine.asyncGetParsedRules(), + [workerEngine], + defaultValue + ) +} + +/** + * This hook is used to make a shallow copy of the worker engine. + */ +export const useShallowCopy = ( + workerEngine: WorkerEngine +): WorkerEngine | undefined => { + const [transition, startTransition] = useTransition() + + const [situationVersion, setSituationVersion] = useState(0) + + const workerEngineShallowCopy = usePromise(async () => { + const copy = await workerEngine.asyncShallowCopy(() => { + console.log('onSituationChange in shallow copy', copy.engineId) + + startTransition(() => { + setSituationVersion((x) => x + 1) + }) + }) + + return copy + }, [workerEngine]) + + useEffect( + () => () => { + console.log('deleteShallowCopy', workerEngineShallowCopy?.engineId) + + void workerEngineShallowCopy?.asyncDeleteShallowCopy() + }, + [workerEngineShallowCopy] + ) + + const memo = useMemo( + () => + workerEngineShallowCopy + ? { ...workerEngineShallowCopy, situationVersion } + : undefined, + [situationVersion, workerEngineShallowCopy] + ) + + return memo +} + +export function useInversionFail() { + // return useContext(EngineContext).inversionFail() +}