Affiche les questions dans une Popover lors de la modification depuis la situation

pull/2080/head
Johan Girod 2022-03-31 11:27:23 +02:00
parent c0abfcfc52
commit ffc00310d4
4 changed files with 74 additions and 66 deletions

View File

@ -1,8 +1,9 @@
import { resetSimulation, stepAction, updateSituation } from '@/actions/actions'
import { resetSimulation, updateSituation } from '@/actions/actions'
import { resetCompany } from '@/actions/companyActions'
import Emoji from '@/components/utils/Emoji'
import { useEngine } from '@/components/utils/EngineContext'
import { useNextQuestions } from '@/components/utils/useNextQuestion'
import { PopoverWithTrigger } from '@/design-system'
import { Button } from '@/design-system/buttons'
import { Spacing } from '@/design-system/layout'
import { H2, H3 } from '@/design-system/typography/heading'
@ -12,14 +13,16 @@ import {
companySituationSelector,
situationSelector,
} from '@/selectors/simulationSelectors'
import { evaluateQuestion } from '@/utils'
import { Grid } from '@mui/material'
import { DottedName } from 'modele-social'
import { EvaluatedNode } from 'publicodes'
import { useCallback, useEffect, useMemo, useState, useRef } from 'react'
import { useCallback, useMemo } from 'react'
import { Trans } from 'react-i18next'
import { useDispatch, useSelector } from 'react-redux'
import styled from 'styled-components'
import Value from '../EngineValue'
import { ExplicableRule } from './Explicable'
import RuleInput from './RuleInput'
type AnswerListProps = {
@ -158,63 +161,51 @@ function StepsTable({
function AnswerElement(
rule: EvaluatedNode & { nodeKind: 'rule'; dottedName: DottedName }
) {
const [isEditing, setEditing] = useState(false)
const dispatch = useDispatch()
const ruleInputRef = useRef<HTMLDivElement | null>(null)
useEffect(() => {
const onClickOutside = (click: MouseEvent) => {
if (!ruleInputRef.current) {
return
}
if (
click.target instanceof HTMLElement &&
ruleInputRef.current.contains(click.target)
) {
return
}
setEditing(false)
}
window.addEventListener('click', onClickOutside)
return () => window.removeEventListener('click', onClickOutside)
}, [])
const situation = useSelector(situationSelector)
const dottedName = rule.dottedName
const handleChange = useCallback(
(value) => {
dispatch(updateSituation(rule.dottedName, value))
if (!(rule.dottedName in situation)) {
dispatch(stepAction(rule.dottedName))
}
dispatch(updateSituation(dottedName, value))
},
[dispatch, rule.dottedName, situation]
[dispatch, dottedName]
)
const handleSubmit = useCallback(() => {
setEditing(false)
}, [])
const engine = useEngine()
return rule.rawNode.question ? (
isEditing ? (
<div ref={ruleInputRef}>
<form onSubmit={handleSubmit}>
<RuleInput
dottedName={rule.dottedName}
onChange={handleChange}
autoFocus
showSuggestions={false}
onBlur={handleSubmit}
onSubmit={handleSubmit}
/>
</form>
</div>
) : (
<Link onPress={() => setEditing(true)} title="Modifier">
<Value expression={rule.dottedName} linkToRule={false} />{' '}
<Emoji emoji="✏" alt="Modifier" />
</Link>
)
<PopoverWithTrigger
small
trigger={(buttonProps) => (
<Link {...buttonProps} title="Modifier">
<Value expression={rule.dottedName} linkToRule={false} />{' '}
<Emoji emoji="✏" alt="Modifier" />
</Link>
)}
>
{(onClose) => (
<>
<form onSubmit={onClose}>
<H3>
{evaluateQuestion(engine, engine.getRule(rule.dottedName))}
<ExplicableRule light dottedName={rule.dottedName} />
</H3>
<RuleInput
dottedName={rule.dottedName}
onChange={handleChange}
autoFocus
showSuggestions={false}
onSubmit={onClose}
/>
</form>
<Spacing lg />
<Button size="XS" onPress={onClose}>
Continuer
</Button>
<Spacing md />
</>
)}
</PopoverWithTrigger>
) : (
<Value expression={rule.dottedName} linkToRule={false} />
)

View File

@ -3550,10 +3550,16 @@ contrat salarié . statut JEI:
Par simplification, le bénéfice de lexonération au titre dun salarié sera considéré comme acquis dès lors que la moitié de son temps de travail au moins est consacrée à un ou des projets de recherche et de développement et lexonération ne pourra être remise en cause.
question.en: '[automatic] Does the person benefit from the Young Innovative
Company (JEI) exemption?'
question.fr: La personne bénéficie-t-elle de l'exonération Jeune Entreprise
Innovante (JEI) ?
question.en: '[automatic] '
question.fr:
variations:
- alors:
texte: Bénéficiez-vous de l'exonération Jeune Entreprise Innovante (JEI) ?
si: dirigeant
- sinon:
texte:
Le salarié bénéficie-t-il de l'exonération Jeune Entreprise Innovante
(JEI) ?
titre.en: JEI status
titre.fr: Statut JEI
contrat salarié . statut JEI . exonération de cotisations:
@ -5169,11 +5175,10 @@ dirigeant . indépendant . PL . PAMC . remplaçant:
Les practicien et auxiliaire médical exerçant une activité de remplacement
ne sont pas redevables de la contribution aux unions régionales des
professionnels de santé (CURPS)
question.en: '[automatic] On 1 January 2020, were you working exclusively as a
replacement?'
question.en: '[automatic] '
question.fr:
Au 1er janvier 2020, exerciez-vous votre activité exclusivement en
tant que remplaçant ?
texte: Au {{ période . début d'année }}, exerciez-vous votre activité
exclusivement en tant que remplaçant ?
titre.en: '[automatic] replacing'
titre.fr: remplaçant
dirigeant . indépendant . PL . PAMC . revenus activité conventionnée:
@ -9133,8 +9138,14 @@ situation personnelle . domiciliation fiscale à l'étranger:
Une cotisation maladie majorée de 14,5% sera en revanche applicable.
question.en: "[automatic] Is the person's tax residence located abroad?"
question.fr: La résidence fiscale de la personne est-elle située à l'étranger ?
question.en: '[automatic] '
question.fr:
variations:
- alors:
texte: Votre résidence fiscale est-elle située à l'étranger ?
si: dirigeant
- sinon:
texte: La résidence fiscale du salarié est-elle située à l'étranger ?
titre.en: '[automatic] Tax residence outside France'
titre.fr: Résidence fiscale hors de France
établissement:

View File

@ -1,4 +1,3 @@
import { Grid } from '@mui/material'
import RuleInput from '@/components/conversation/RuleInput'
import { WhenApplicable, WhenNotApplicable } from '@/components/EngineValue'
import PageHeader from '@/components/PageHeader'
@ -11,9 +10,11 @@ import { Button } from '@/design-system/buttons'
import { Spacing } from '@/design-system/layout'
import { headings } from '@/design-system/typography'
import { Intro, SmallBody } from '@/design-system/typography/paragraphs'
import { evaluateQuestion, hash } from '@/utils'
import { Grid } from '@mui/material'
import { DottedName } from 'modele-social'
import Engine, { PublicodesExpression } from 'publicodes'
import { isEmpty, omit } from 'ramda'
import { omit } from 'ramda'
import {
Fragment,
lazy,
@ -23,7 +24,6 @@ import {
useState,
} from 'react'
import { TrackPage } from '../../../ATInternetTracking'
import { hash } from '@/utils'
import formulaire from './demande-mobilité.yaml'
import picture from './undraw_Traveling_re_weve.svg'

View File

@ -1,4 +1,9 @@
import Engine, { formatValue, Rule, RuleNode } from 'publicodes'
import Engine, {
formatValue,
PublicodesExpression,
Rule,
RuleNode,
} from 'publicodes'
export function capitalise0(name: undefined): undefined
export function capitalise0(name: string): string
@ -212,7 +217,8 @@ export function evaluateQuestion(
question.rawNode.question &&
typeof question.rawNode.question === 'object'
) {
return engine.evaluate(question.rawNode.question).nodeValue as string
return engine.evaluate(question.rawNode.question as PublicodesExpression)
.nodeValue as string
}
return question.rawNode.question