✨ Crée un hook useSituationConfig
parent
935e687373
commit
77add355aa
|
@ -1,6 +1,6 @@
|
|||
import { SitePaths } from 'Components/utils/SitePathsContext'
|
||||
import { History } from 'history'
|
||||
import { RootState, SimulationConfig } from 'Reducers/rootReducer'
|
||||
import { RootState, SimulationConfig, Situation } from 'Reducers/rootReducer'
|
||||
import { ThunkAction } from 'redux-thunk'
|
||||
import { DottedName } from 'modele-social'
|
||||
import { deletePersistedSimulation } from '../storage/persistSimulation'
|
||||
|
@ -34,17 +34,11 @@ type StepAction = {
|
|||
step: DottedName
|
||||
}
|
||||
|
||||
type SetSimulationConfigAction = {
|
||||
type: 'SET_SIMULATION'
|
||||
url: string
|
||||
config: SimulationConfig
|
||||
useCompanyDetails: boolean
|
||||
}
|
||||
|
||||
type DeletePreviousSimulationAction = {
|
||||
type: 'DELETE_PREVIOUS_SIMULATION'
|
||||
}
|
||||
|
||||
type SetSimulationConfigAction = ReturnType<typeof setSimulationConfig>
|
||||
type ResetSimulationAction = ReturnType<typeof resetSimulation>
|
||||
type UpdateAction = ReturnType<typeof updateSituation>
|
||||
type UpdateSituationAction = ReturnType<typeof updateSituation>
|
||||
|
@ -89,19 +83,15 @@ export const setSituationBranch = (id: number) =>
|
|||
|
||||
export const setSimulationConfig = (
|
||||
config: SimulationConfig,
|
||||
useCompanyDetails = false
|
||||
): ThunkResult<void> => (dispatch, getState, { history }): void => {
|
||||
if (getState().simulation?.config === config) {
|
||||
return
|
||||
}
|
||||
const url = history.location.pathname
|
||||
dispatch({
|
||||
url: string,
|
||||
initialSituation?: Situation
|
||||
) =>
|
||||
({
|
||||
type: 'SET_SIMULATION',
|
||||
url,
|
||||
useCompanyDetails,
|
||||
config,
|
||||
})
|
||||
}
|
||||
initialSituation,
|
||||
} as const)
|
||||
|
||||
export const setActiveTarget = (targetName: DottedName) =>
|
||||
({
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { setSimulationConfig } from 'Actions/actions'
|
||||
import {
|
||||
defineDirectorStatus,
|
||||
isAutoentrepreneur,
|
||||
|
@ -19,6 +18,7 @@ import InfoBulle from 'Components/ui/InfoBulle'
|
|||
import './SchemeComparaison.css'
|
||||
import { engineOptions, useEngine } from './utils/EngineContext'
|
||||
import { DottedName } from 'modele-social'
|
||||
import useSimulationConfig from './utils/useSimulationConfig'
|
||||
|
||||
type SchemeComparaisonProps = {
|
||||
hideAutoEntrepreneur?: boolean
|
||||
|
@ -29,10 +29,8 @@ export default function SchemeComparaison({
|
|||
hideAutoEntrepreneur = false,
|
||||
hideAssimiléSalarié = false,
|
||||
}: SchemeComparaisonProps) {
|
||||
useSimulationConfig(dirigeantComparaison)
|
||||
const dispatch = useDispatch()
|
||||
useEffect(() => {
|
||||
dispatch(setSimulationConfig(dirigeantComparaison))
|
||||
}, [])
|
||||
const engine = useEngine()
|
||||
const plafondAutoEntrepreneurDépassé =
|
||||
engine.evaluate(
|
||||
|
|
|
@ -36,6 +36,7 @@ export default function Conversation({ customEndMessages }: ConversationProps) {
|
|||
dispatch(goToQuestion(currentQuestion))
|
||||
}
|
||||
}, [dispatch, currentQuestion])
|
||||
|
||||
const setDefault = () =>
|
||||
dispatch(
|
||||
// TODO: Skiping a question shouldn't be equivalent to answering the
|
||||
|
@ -46,6 +47,15 @@ export default function Conversation({ customEndMessages }: ConversationProps) {
|
|||
undefined
|
||||
)
|
||||
)
|
||||
// TODO: Skiping a question shouldn't be equivalent to answering the
|
||||
// default value (for instance the question shouldn't appear in the
|
||||
// answered questions).
|
||||
dispatch({
|
||||
type: 'STEP_ACTION',
|
||||
name: 'fold',
|
||||
step: currentQuestion,
|
||||
})
|
||||
|
||||
const goToPrevious = () =>
|
||||
dispatch(goToQuestion(previousAnswers.slice(-1)[0]))
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
import { setSimulationConfig } from 'Actions/actions'
|
||||
import { useEffect } from 'react'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { useHistory } from 'react-router'
|
||||
import { Company } from 'Reducers/inFranceAppReducer'
|
||||
import { RootState, SimulationConfig, Situation } from 'Reducers/rootReducer'
|
||||
|
||||
export default function useSituationConfig(
|
||||
config: SimulationConfig | undefined,
|
||||
{ useExistingCompanyFromSituation = false } = {}
|
||||
) {
|
||||
const dispatch = useDispatch()
|
||||
const url = useHistory().location.pathname
|
||||
const lastUrl = useSelector((state: RootState) => state.simulation?.url)
|
||||
const existingCompany = useSelector(
|
||||
(state: RootState) => state.inFranceApp.existingCompany
|
||||
)
|
||||
const initialSituation = useExistingCompanyFromSituation
|
||||
? getCompanySituation(existingCompany)
|
||||
: undefined
|
||||
|
||||
useEffect(() => {
|
||||
if (config && url !== lastUrl) {
|
||||
dispatch(setSimulationConfig(config ?? {}, url, initialSituation))
|
||||
}
|
||||
}, [config, url, lastUrl, initialSituation])
|
||||
}
|
||||
|
||||
export function getCompanySituation(company: Company | null): Situation {
|
||||
return {
|
||||
...(company?.localisation && {
|
||||
'établissement . localisation': { objet: company.localisation },
|
||||
}),
|
||||
...(company?.dateDeCréation && {
|
||||
'entreprise . date de création': company.dateDeCréation.replace(
|
||||
/(.*)-(.*)-(.*)/,
|
||||
'$3/$2/$1'
|
||||
),
|
||||
}),
|
||||
}
|
||||
}
|
|
@ -7,6 +7,8 @@ import { DottedName } from 'modele-social'
|
|||
import { objectifsSelector } from '../selectors/simulationSelectors'
|
||||
import inFranceAppReducer, { Company } from './inFranceAppReducer'
|
||||
import storageRootReducer from './storageReducer'
|
||||
import { Names } from 'modele-social/dist/names'
|
||||
import { getCompanySituation } from 'Components/utils/useSimulationConfig'
|
||||
|
||||
function explainedVariable(
|
||||
state: DottedName | null = null,
|
||||
|
@ -48,18 +50,18 @@ type QuestionsKind =
|
|||
| 'liste'
|
||||
| 'liste noire'
|
||||
|
||||
export type SimulationConfig = {
|
||||
objectifs?:
|
||||
export type SimulationConfig = Partial<{
|
||||
objectifs:
|
||||
| Array<DottedName>
|
||||
| Array<{ icône: string; nom: string; objectifs: Array<DottedName> }>
|
||||
'objectifs cachés'?: Array<DottedName>
|
||||
situation: Simulation['situation']
|
||||
bloquant?: Array<DottedName>
|
||||
questions?: Partial<Record<QuestionsKind, Array<DottedName>>>
|
||||
branches?: Array<{ nom: string; situation: SimulationConfig['situation'] }>
|
||||
bloquant: Array<DottedName>
|
||||
questions: Partial<Record<QuestionsKind, Array<DottedName>>>
|
||||
branches: Array<{ nom: string; situation: SimulationConfig['situation'] }>
|
||||
'unité par défaut': string
|
||||
color?: string
|
||||
}
|
||||
color: string
|
||||
}>
|
||||
|
||||
export type Situation = Partial<Record<DottedName, any>>
|
||||
export type Simulation = {
|
||||
|
@ -72,44 +74,25 @@ export type Simulation = {
|
|||
foldedSteps: Array<DottedName>
|
||||
unfoldedStep?: DottedName | null
|
||||
}
|
||||
function getCompanySituation(company: Company | null): Situation {
|
||||
return {
|
||||
...(company?.localisation && {
|
||||
'établissement . localisation': { objet: company.localisation },
|
||||
}),
|
||||
...(company?.dateDeCréation && {
|
||||
'entreprise . date de création': company.dateDeCréation.replace(
|
||||
/(.*)-(.*)-(.*)/,
|
||||
'$3/$2/$1'
|
||||
),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
function simulation(
|
||||
state: Simulation | null = null,
|
||||
action: Action,
|
||||
existingCompany: Company
|
||||
action: Action
|
||||
): Simulation | null {
|
||||
if (action.type === 'SET_SIMULATION') {
|
||||
if (state && state.config === action.config) {
|
||||
return state
|
||||
}
|
||||
const companySituation = action.useCompanyDetails
|
||||
? getCompanySituation(existingCompany)
|
||||
: {}
|
||||
const { config, url } = action
|
||||
const { config, url, initialSituation } = action
|
||||
return {
|
||||
config,
|
||||
url,
|
||||
hiddenNotifications: [],
|
||||
situation: companySituation,
|
||||
initialSituation: companySituation,
|
||||
situation: initialSituation ?? {},
|
||||
initialSituation: initialSituation ?? {},
|
||||
targetUnit: config['unité par défaut'] || '€/mois',
|
||||
foldedSteps: Object.keys(companySituation) as Array<DottedName>,
|
||||
foldedSteps: Object.keys(initialSituation ?? {}) as Array<Names>,
|
||||
unfoldedStep: null,
|
||||
}
|
||||
}
|
||||
|
||||
if (state === null) {
|
||||
return state
|
||||
}
|
||||
|
@ -188,22 +171,19 @@ const existingCompanyReducer = (state: RootState, action: Action) => {
|
|||
}
|
||||
return state
|
||||
}
|
||||
const mainReducer = (state: any, action: Action) =>
|
||||
combineReducers({
|
||||
explainedVariable,
|
||||
// We need to access the `rules` in the simulation reducer
|
||||
simulation: (a: Simulation | null = null, b: Action): Simulation | null =>
|
||||
simulation(a, b, state?.inFranceApp?.existingCompany),
|
||||
previousSimulation: defaultTo(null) as Reducer<SavedSimulation | null>,
|
||||
situationBranch,
|
||||
activeTargetInput,
|
||||
inFranceApp: inFranceAppReducer,
|
||||
})(state, action)
|
||||
const mainReducer = combineReducers({
|
||||
explainedVariable,
|
||||
simulation,
|
||||
previousSimulation: defaultTo(null) as Reducer<SavedSimulation | null>,
|
||||
situationBranch,
|
||||
activeTargetInput,
|
||||
inFranceApp: inFranceAppReducer,
|
||||
})
|
||||
|
||||
export default reduceReducers<RootState>(
|
||||
mainReducer as any,
|
||||
existingCompanyReducer as any,
|
||||
storageRootReducer as any
|
||||
mainReducer,
|
||||
existingCompanyReducer as Reducer<RootState>,
|
||||
storageRootReducer as Reducer<RootState>
|
||||
) as Reducer<RootState>
|
||||
|
||||
export type RootState = ReturnType<typeof mainReducer>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { setSimulationConfig, updateSituation } from 'Actions/actions'
|
||||
import { updateSituation } from 'Actions/actions'
|
||||
import Aide from 'Components/conversation/Aide'
|
||||
import { Explicable, ExplicableRule } from 'Components/conversation/Explicable'
|
||||
import RuleInput from 'Components/conversation/RuleInput'
|
||||
|
@ -11,6 +11,7 @@ import { EngineContext, useEngine } from 'Components/utils/EngineContext'
|
|||
import { ScrollToTop } from 'Components/utils/Scroll'
|
||||
import useDisplayOnIntersecting from 'Components/utils/useDisplayOnIntersecting'
|
||||
import { useNextQuestions } from 'Components/utils/useNextQuestion'
|
||||
import useSimulationConfig from 'Components/utils/useSimulationConfig'
|
||||
import { DottedName } from 'modele-social'
|
||||
import { RuleNode } from 'publicodes'
|
||||
import { Fragment, useCallback, useContext, useEffect } from 'react'
|
||||
|
@ -24,15 +25,13 @@ import { CompanySection } from '../Home'
|
|||
import simulationConfig from './config.yaml'
|
||||
|
||||
export default function AideDéclarationIndépendant() {
|
||||
useSimulationConfig(simulationConfig)
|
||||
const dispatch = useDispatch()
|
||||
const engine = useEngine()
|
||||
|
||||
const company = useSelector(
|
||||
(state: RootState) => state.inFranceApp.existingCompany
|
||||
)
|
||||
useEffect(() => {
|
||||
dispatch(setSimulationConfig(simulationConfig, true))
|
||||
}, [dispatch])
|
||||
|
||||
const [resultsRef, resultsInViewPort] = useDisplayOnIntersecting({
|
||||
threshold: 0.5,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { setSimulationConfig } from 'Actions/actions'
|
||||
import useSimulationConfig from 'Components/utils/useSimulationConfig'
|
||||
import { DistributionBranch } from 'Components/Distribution'
|
||||
import Value, { Condition } from 'Components/EngineValue'
|
||||
import SimulateurWarning from 'Components/SimulateurWarning'
|
||||
|
@ -16,10 +16,7 @@ import styled from 'styled-components'
|
|||
import config from './configs/artiste-auteur.yaml'
|
||||
|
||||
export default function ArtisteAuteur() {
|
||||
const dispatch = useDispatch()
|
||||
useEffect(() => {
|
||||
dispatch(setSimulationConfig(config))
|
||||
}, [])
|
||||
useSimulationConfig(config)
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { setSimulationConfig, updateSituation } from 'Actions/actions'
|
||||
import { updateSituation } from 'Actions/actions'
|
||||
import RuleInput from 'Components/conversation/RuleInput'
|
||||
import Value from 'Components/EngineValue'
|
||||
import Notifications from 'Components/Notifications'
|
||||
|
@ -6,27 +6,20 @@ import { SimulationGoal, SimulationGoals } from 'Components/SimulationGoals'
|
|||
import Animate from 'Components/ui/animate'
|
||||
import Warning from 'Components/ui/WarningBlock'
|
||||
import { ThemeColorsContext } from 'Components/utils/colors'
|
||||
import { useContext, useEffect } from 'react'
|
||||
import useSimulationConfig from 'Components/utils/useSimulationConfig'
|
||||
import { useContext } from 'react'
|
||||
import emoji from 'react-easy-emoji'
|
||||
import { Trans } from 'react-i18next'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { situationSelector } from 'Selectors/simulationSelectors'
|
||||
|
||||
const config = {
|
||||
color: '',
|
||||
'unité par défaut': '€/an',
|
||||
situation: {},
|
||||
}
|
||||
export default function ISSimulation() {
|
||||
const dispatch = useDispatch()
|
||||
const { color } = useContext(ThemeColorsContext)
|
||||
useEffect(() => {
|
||||
// HACK The config is mutated to avoid reseting the situation everytime the
|
||||
// component is loaded. `setSimulationConfig` relies on config object
|
||||
// equality. The `setSimulationConfig` design should be improved.
|
||||
config.color = color
|
||||
dispatch(setSimulationConfig(config))
|
||||
}, [])
|
||||
useSimulationConfig({
|
||||
color,
|
||||
'unité par défaut': '€/an',
|
||||
situation: {},
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { setSimulationConfig } from 'Actions/actions'
|
||||
import { ThemeColorsProvider } from 'Components/utils/colors'
|
||||
import { IsEmbeddedContext } from 'Components/utils/embeddedContext'
|
||||
import Meta from 'Components/utils/Meta'
|
||||
import useSimulationConfig from 'Components/utils/useSimulationConfig'
|
||||
import { default as React, useContext, useEffect } from 'react'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import { SimulatorData } from './metadata'
|
||||
|
||||
|
@ -16,14 +15,8 @@ export default function SimulateurPage({
|
|||
seoExplanations,
|
||||
}: SimulatorData[keyof SimulatorData]) {
|
||||
const inIframe = useContext(IsEmbeddedContext)
|
||||
const dispatch = useDispatch()
|
||||
const fromGérer = !!useLocation<{ fromGérer?: boolean }>().state?.fromGérer
|
||||
useEffect(() => {
|
||||
if (!config) {
|
||||
return
|
||||
}
|
||||
dispatch(setSimulationConfig(config, fromGérer))
|
||||
}, [config])
|
||||
useSimulationConfig(config, { useExistingCompanyFromSituation: fromGérer })
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
Loading…
Reference in New Issue