engine-in-web-worker
Jérémy Rialland 2023-08-09 19:34:14 +02:00
parent c1923b6eef
commit cab0ff083c
29 changed files with 363 additions and 306 deletions

View File

@ -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 (

View File

@ -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]

View File

@ -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<Names extends string>({
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<Names extends string>({
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]
)

View File

@ -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'

View File

@ -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({
<I18nextProvider i18n={i18next}>
<ReduxProvider store={store}>
<BrowserRouterProvider basename={basename}>
<WorkerEngineProvider
basename={basename}
workerClient={workerClient}
>
<WorkerEngineProvider workerClient={workerClient}>
<ErrorBoundary
fallback={(errorData) => (
// eslint-disable-next-line react/jsx-props-no-spreading

View File

@ -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)

View File

@ -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]
)

View File

@ -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 ?? {}

View File

@ -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<keyof AbsoluteSitePaths['simulateurs'], 'index'>
@ -20,7 +18,7 @@ export default function SimulateurWarning({
simulateur,
}: SimulateurWarningProps) {
const workerEngine = useWorkerEngine()
const year = usePromiseOnSituationChange(
const year = usePromise(
() => workerEngine.asyncEvaluate('date'),
[workerEngine]
)

View File

@ -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,

View File

@ -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 }) => ({

View File

@ -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<EvaluatedNode>
) as Promise<RuleNode<DottedName>>
)
),
[nextQuestions, workerEngine],
[] as EvaluatedRule[]
[] as RuleNode<DottedName>[]
)
const situationQuestions = useMemo(
@ -272,7 +266,7 @@ export default function AnswerList({ onClose, children }: AnswerListProps) {
function StepsTable({
rules,
}: {
rules: Array<EvaluatedRule | RuleNode>
rules: Array<RuleNode>
onClose: () => void
}) {
const { t } = useTranslation()

View File

@ -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]
)

View File

@ -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'

View File

@ -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 (
<>
<Checkbox
defaultSelected={evaluation.nodeValue === true}
defaultSelected={evaluation?.nodeValue === true}
id={`checkbox-input-${node.dottedName.replace(/\s|\./g, '_')}`}
label={node.title}
onChange={(isSelected) => onChange(isSelected)}

View File

@ -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' &&

View File

@ -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()

View File

@ -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 }

View File

@ -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
}

View File

@ -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

View File

@ -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(() => {

View File

@ -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' ? (

View File

@ -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(

View File

@ -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 ?? {}

View File

@ -44,6 +44,7 @@ const logger = {
const init = ({ basename }: Pick<ProviderProps, 'basename'>) => {
let rules = rawRules
if (basename === 'infrance') {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
rules = translateRules('en', ruleTranslations, rules)

View File

@ -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, K extends keyof T> = T extends unknown
? Omit<T, K>
: never
export type WorkerEngineAction<
Actions extends WorkerEngineActions,
Action extends Actions['action'],
> = Extract<Actions, { action: Action }>
type GenericParams = {
/**
@ -60,24 +61,24 @@ type GenericParams = {
id: number
}
export type WorkerEngineAction<
Acts extends WorkerEngineActions<unknown[], string>,
T extends Acts['action'],
> = Extract<Acts, { action: T }>
type DistributiveOmit<T, K extends keyof T> = T extends unknown
? Omit<T, K>
: never
/**
*/
export const createWorkerEngine = <
Name extends string,
EngineType extends Engine<Name>,
Name extends string = string,
InitParams extends unknown[] = unknown[],
>(
init: (...params: InitParams) => EngineType
init: (...params: InitParams) => Engine<Name>
) => {
type Params = DistributiveOmit<
WorkerEngineActions<InitParams, Name> & GenericParams,
'result'
>
let engines: (EngineType | undefined)[] = []
let engines: (Engine<Name> | 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') {

View File

@ -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, Name>,
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, Name>,
InitParams extends unknown[] = unknown[],
Name extends string = string,
Actions extends WorkerEngineActions = WorkerEngineActions,
// Promises extends WorkerEnginePromise = WorkerEnginePromise,
// >
// Actions extends WorkerEngineActions<InitParams, Name>,
// InitParams extends unknown[] = unknown[],
// Name extends string = string,
> {
engineId: number
promises: WorkerEnginePromise<Actions>[]
@ -41,17 +45,10 @@ interface Ctx<
isWorkerReady: Promise<number>
}
export type WorkerEngineClient<
Actions extends WorkerEngineActions<InitParams, Name>,
InitParams extends unknown[] = unknown[],
Name extends string = string,
> = ReturnType<typeof createWorkerEngineClient<Actions, InitParams, Name>>
export type WorkerEngineClient<Actions extends WorkerEngineActions> =
ReturnType<typeof createWorkerEngineClient<Actions>>
export const createWorkerEngineClient = <
Actions extends WorkerEngineActions<InitParams, Name>,
InitParams extends unknown[] = unknown[],
Name extends string = string,
>(
export const createWorkerEngineClient = <Actions extends WorkerEngineActions>(
worker: Worker,
options: {
initParams: WorkerEngineAction<Actions, 'init'>['params']
@ -116,53 +113,30 @@ export const createWorkerEngineClient = <
const workerEngine = workerEngineConstruct(ctx, { onSituationChange })
void postMessage(ctx, 'setSituation')
return workerEngine
}
// type ActionType<
// Actions extends WorkerEngineActions<InitParams, Name>,
// ActionNames extends Actions['action'],
// InitParams extends unknown[] = unknown[],
// Name extends string = string,
// > = WorkerEngineAction<Actions, ActionNames>
// type Action<T extends Actions['action']> = WorkerEngineAction<Actions, T>
// const postMessage = async <T extends Actions['action'], U extends Action<T>>(
// 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<InitParams, Name>,
Action extends WorkerEngineAction<Actions, ActionNames>,
Actions extends WorkerEngineActions,
ActionNames extends Actions['action'],
InitParams extends unknown[] = unknown[],
Name extends string = string,
Action extends WorkerEngineAction<Actions, ActionNames>,
>(
// ActionNames extends Actions['action'],
// Actions extends WorkerEngineActions<InitParams, Name>,
// InitParams extends unknown[] = unknown[],
// Name extends string = string,
// Action extends Actions['action'],
// Actions extends WorkerEngineActions<InitParams, Name>,
// InitParams extends unknown[] = unknown[],
// Name extends string = string,
ctx: Ctx<Actions>,
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, Name>,
InitParams extends unknown[] = unknown[],
Name extends string = string,
>(
/**
*/
const wrappedPostMessage =
(ctx: Ctx) =>
<
Actions extends WorkerEngineActions,
ActionNames extends Actions['action'],
Action extends WorkerEngineAction<Actions, ActionNames>,
>(
action: ActionNames,
...params: Action['params']
) =>
postMessage<Actions, ActionNames, Action>(ctx, action, ...params)
/**
*/
const workerEngineConstruct = <Actions extends WorkerEngineActions>(
ctx: Ctx<Actions>,
options: {
// engineId: number
// worker: Worker
// isWorkerReady: Promise<Extract<Actions, { action: 'init' }>['result']>
onSituationChange?: (engineId: number) => void
// postMessage: <
// T extends Actions['action'],
// U extends Extract<Actions, { action: T }>,
// >(
// engineId: number,
// action: T,
// ...params: U['params']
// ) => Promise<U['result']>
}
) => {
type Act<T extends Actions['action']> = WorkerEngineAction<Actions, T>
// const yyyy = <
// ActionNames extends Actions['action'],
// Act extends Action<ActionNames, Actions>,
// Actions extends WorkerEngineActions<InitParams, Name>,
// 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<ActionNames, Actions>,
// >(
// action: ActionNames,
// ...params: Act['params']
// ): Promise<Act['result']>
// }
const wrappedPostMessage =
(ctx: Ctx<Actions>) =>
<
ActionNames extends Actions['action'],
Action extends WorkerEngineAction<Actions, ActionNames>,
>(
action: ActionNames,
...params: Action['params']
) =>
postMessage(ctx, action, ...params)
// await postMessage(ctx, '')
// await wrappedPostMessage(ctx)('')
// await wrappedPostMessage(ctx)('')
type Action<T extends Actions['action']> = WorkerEngineAction<Actions, T>
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<Act<'setSituation'>['result']> => {
// abort every action "evaluate"
// promises.forEach((promise) => {
// if (engineId === promise.engineId && promise.action === 'evaluate') {
// promise.reject?.('abort')
// }
// })
...params: Action<'setSituation'>['params']
): Promise<Action<'setSituation'>['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<Act<'evaluate'>['result']> => {
...params: Action<'evaluate'>['params']
): Promise<Action<'evaluate'>['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<Act<'getRule'>['result']> => {
...params: Action<'getRule'>['params']
): Promise<Action<'getRule'>['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<Act<'getParsedRules'>['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')
},

View File

@ -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<Actions>
) => {
const [transition, startTransition] = useTransition()
const [situationVersion, setSituationVersion] = useState(0)
const [workerEngine, setWorkerEngine] = useState<WorkerEngineClient<Actions>>(
() => {
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<typeof useSynchronizedWorkerEngine>
>
const WorkerEngineContext = createContext<WorkerEngine>(
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<Actions>
children: React.ReactNode
}) => {
const workerEngine = useSynchronizedWorkerEngine(workerClient)
useSetupSafeSituation(workerEngine)
if (workerEngine === undefined) {
return children
}
return (
<WorkerEngineContext.Provider value={workerEngine}>
{children}
</WorkerEngineContext.Provider>
)
}
interface Options<DefaultValue> {
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<DefaultValue> = {}
) => {
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<DefaultValue> = {}) => {
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()
}