Ajout de l'option "allowJs" dans tsconfig.js
Cela permet l'inférence de type à partir des fichiers js qui ne sont pas encore convertis en TypeScript. Par ailleurs suppression des dernières traces de Flow. Ajout d'options plus strictes pour dans la config tsconfig.jspull/810/head
parent
34085d3b31
commit
1b963b8bbe
|
@ -25,7 +25,6 @@ env:
|
|||
settings:
|
||||
react:
|
||||
version: 'detect'
|
||||
flowVersion: '0.92'
|
||||
|
||||
overrides:
|
||||
- files: ['*.test.js', 'cypress/integration/**/*.js']
|
||||
|
@ -39,7 +38,6 @@ extends:
|
|||
- eslint:recommended
|
||||
- plugin:react/recommended
|
||||
- prettier
|
||||
- prettier/flowtype
|
||||
- prettier/react
|
||||
parserOptions:
|
||||
ecmaFeatures:
|
||||
|
|
|
@ -5,6 +5,5 @@ dist/
|
|||
.DS_Store
|
||||
package-lock.json
|
||||
yarn-error.log
|
||||
flow-typed/
|
||||
cypress/videos
|
||||
cypress/screenshots
|
||||
|
|
|
@ -9,8 +9,7 @@ module.exports = {
|
|||
}
|
||||
],
|
||||
'@babel/react',
|
||||
'@babel/preset-typescript',
|
||||
'@babel/flow'
|
||||
'@babel/preset-typescript'
|
||||
],
|
||||
plugins: [
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
|
|
|
@ -101,7 +101,6 @@
|
|||
"@babel/plugin-proposal-optional-chaining": "^7.0.0",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
|
||||
"@babel/preset-env": "^7.6.3",
|
||||
"@babel/preset-flow": "^7.0.0-beta.51",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@babel/preset-typescript": "^7.6.0",
|
||||
"@types/classnames": "^2.2.9",
|
||||
|
@ -113,6 +112,7 @@
|
|||
"@types/react-color": "^3.0.1",
|
||||
"@types/react-dom": "^16.9.3",
|
||||
"@types/react-helmet": "^5.0.13",
|
||||
"@types/react-highlight-words": "^0.16.0",
|
||||
"@types/react-redux": "^7.1.5",
|
||||
"@types/react-router": "^5.1.2",
|
||||
"@types/react-router-dom": "^5.1.0",
|
||||
|
|
|
@ -20,7 +20,7 @@ export type Action =
|
|||
| UpdateDefaultUnit
|
||||
| SetActiveTargetAction
|
||||
|
||||
type ThunkResult<R> = ThunkAction<
|
||||
export type ThunkResult<R> = ThunkAction<
|
||||
R,
|
||||
RootState,
|
||||
{ history: History; sitePaths: SitePaths },
|
||||
|
@ -74,7 +74,7 @@ export const goToQuestion = (question: string) =>
|
|||
|
||||
export const validateStepWithValue = (
|
||||
dottedName: DottedName,
|
||||
value: any
|
||||
value: unknown
|
||||
): ThunkResult<void> => dispatch => {
|
||||
dispatch(updateSituation(dottedName, value))
|
||||
dispatch({
|
||||
|
@ -119,7 +119,7 @@ export const deletePreviousSimulation = (): ThunkResult<void> => dispatch => {
|
|||
deletePersistedSimulation()
|
||||
}
|
||||
|
||||
export const updateSituation = (fieldName: DottedName, value: any) =>
|
||||
export const updateSituation = (fieldName: DottedName, value: unknown) =>
|
||||
({
|
||||
type: 'UPDATE_SITUATION',
|
||||
fieldName,
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
|
||||
import { dropWhile, last } from 'ramda'
|
||||
import { nextQuestionUrlSelector } from 'Selectors/companyStatusSelectors'
|
||||
import type {
|
||||
IsSoleProprietorshipAction,
|
||||
CompanyHasMultipleAssociatesAction,
|
||||
DirectorStatus,
|
||||
IsAutoentrepreneurAction,
|
||||
ResetCompanyStatusAction,
|
||||
DirectorIsInAMinorityAction,
|
||||
DefineDirectorStatusAction
|
||||
} from 'Types/companyTypes'
|
||||
import type { Thunk } from 'Types/ActionsTypes'
|
||||
|
||||
// Bug : last et dropline sont automatiquement enlevé par le formatOnSave de visual studio code sinon
|
||||
// eslint-disable-next-line
|
||||
let x = [dropWhile, last]
|
||||
|
||||
const thenGoToNextQuestion = actionCreator => (...args: any) =>
|
||||
((dispatch, getState, { history, sitePaths }) => {
|
||||
dispatch(actionCreator(...args))
|
||||
history.push(nextQuestionUrlSelector(getState(), { sitePaths }))
|
||||
}: Thunk<any>)
|
||||
|
||||
export const isSoleProprietorship = thenGoToNextQuestion(
|
||||
(isSoleProprietorship: ?boolean): IsSoleProprietorshipAction => ({
|
||||
type: 'COMPANY_IS_SOLE_PROPRIETORSHIP',
|
||||
isSoleProprietorship
|
||||
})
|
||||
)
|
||||
|
||||
export const defineDirectorStatus = thenGoToNextQuestion(
|
||||
(status: ?DirectorStatus): DefineDirectorStatusAction => ({
|
||||
type: 'DEFINE_DIRECTOR_STATUS',
|
||||
status
|
||||
})
|
||||
)
|
||||
|
||||
export const companyHasMultipleAssociates = thenGoToNextQuestion(
|
||||
(multipleAssociates: ?boolean): CompanyHasMultipleAssociatesAction => ({
|
||||
type: 'COMPANY_HAS_MULTIPLE_ASSOCIATES',
|
||||
multipleAssociates
|
||||
})
|
||||
)
|
||||
|
||||
export const isAutoentrepreneur = thenGoToNextQuestion(
|
||||
(autoEntrepreneur: ?boolean): IsAutoentrepreneurAction => ({
|
||||
type: 'COMPANY_IS_MICROENTERPRISE',
|
||||
autoEntrepreneur
|
||||
})
|
||||
)
|
||||
|
||||
export const directorIsInAMinority = thenGoToNextQuestion(
|
||||
(minorityDirector: ?boolean): DirectorIsInAMinorityAction => ({
|
||||
type: 'SPECIFY_DIRECTORS_SHARE',
|
||||
minorityDirector
|
||||
})
|
||||
)
|
||||
|
||||
export const goToCompanyStatusChoice = (): Thunk<ResetCompanyStatusAction> => (
|
||||
dispatch,
|
||||
_,
|
||||
{history, sitePaths}
|
||||
) => {
|
||||
dispatch(
|
||||
({
|
||||
type: 'RESET_COMPANY_STATUS_CHOICE'
|
||||
}: ResetCompanyStatusAction)
|
||||
)
|
||||
history.push(sitePaths.créer.index)
|
||||
}
|
||||
|
||||
export const resetCompanyStatusChoice = (
|
||||
from: string
|
||||
): Thunk<ResetCompanyStatusAction> => (dispatch, getState) => {
|
||||
const answeredQuestion = Object.keys(
|
||||
getState().inFranceApp.companyLegalStatus
|
||||
)
|
||||
const answersToReset = dropWhile(a => a !== from, answeredQuestion)
|
||||
if (!answersToReset.length) {
|
||||
return
|
||||
}
|
||||
dispatch({
|
||||
type: 'RESET_COMPANY_STATUS_CHOICE',
|
||||
answersToReset
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
import { dropWhile } from 'ramda'
|
||||
import { nextQuestionUrlSelector } from 'Selectors/companyStatusSelectors'
|
||||
|
||||
const thenGoToNextQuestion = actionCreator => (...args: unknown[]) => (
|
||||
dispatch,
|
||||
getState,
|
||||
{ history, sitePaths }
|
||||
) => {
|
||||
dispatch(actionCreator(...args))
|
||||
history.push(nextQuestionUrlSelector(getState(), { sitePaths }))
|
||||
}
|
||||
|
||||
export const isSoleProprietorship = thenGoToNextQuestion(
|
||||
(isSoleProprietorship?: boolean) =>
|
||||
({
|
||||
type: 'COMPANY_IS_SOLE_PROPRIETORSHIP',
|
||||
isSoleProprietorship
|
||||
} as const)
|
||||
)
|
||||
|
||||
type DirectorStatus = 'SALARIED' | 'SELF_EMPLOYED'
|
||||
|
||||
export const defineDirectorStatus = thenGoToNextQuestion(
|
||||
(status: DirectorStatus) =>
|
||||
({
|
||||
type: 'DEFINE_DIRECTOR_STATUS',
|
||||
status
|
||||
} as const)
|
||||
)
|
||||
|
||||
export const companyHasMultipleAssociates = thenGoToNextQuestion(
|
||||
(multipleAssociates?: boolean) =>
|
||||
({
|
||||
type: 'COMPANY_HAS_MULTIPLE_ASSOCIATES',
|
||||
multipleAssociates
|
||||
} as const)
|
||||
)
|
||||
|
||||
export const isAutoentrepreneur = thenGoToNextQuestion(
|
||||
(autoEntrepreneur?: boolean) =>
|
||||
({
|
||||
type: 'COMPANY_IS_MICROENTERPRISE',
|
||||
autoEntrepreneur
|
||||
} as const)
|
||||
)
|
||||
|
||||
export const directorIsInAMinority = thenGoToNextQuestion(
|
||||
(minorityDirector?: boolean) =>
|
||||
({
|
||||
type: 'SPECIFY_DIRECTORS_SHARE',
|
||||
minorityDirector
|
||||
} as const)
|
||||
)
|
||||
|
||||
export const goToCompanyStatusChoice = () => (
|
||||
dispatch,
|
||||
_,
|
||||
{ history, sitePaths }
|
||||
) => {
|
||||
dispatch({
|
||||
type: 'RESET_COMPANY_STATUS_CHOICE'
|
||||
} as const)
|
||||
history.push(sitePaths.créer.index)
|
||||
}
|
||||
|
||||
export const resetCompanyStatusChoice = (from: string) => (
|
||||
dispatch,
|
||||
getState
|
||||
) => {
|
||||
const answeredQuestion = Object.keys(
|
||||
getState().inFranceApp.companyLegalStatus
|
||||
)
|
||||
const answersToReset = dropWhile(a => a !== from, answeredQuestion)
|
||||
if (!answersToReset.length) {
|
||||
return
|
||||
}
|
||||
dispatch({
|
||||
type: 'RESET_COMPANY_STATUS_CHOICE',
|
||||
answersToReset
|
||||
})
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
import type { FicheDePaie } from 'Types/ResultViewTypes'
|
||||
import withColours from 'Components/utils/withColours'
|
||||
import Value from 'Components/Value'
|
||||
import { findRuleByDottedName, getRuleFromAnalysis } from 'Engine/rules'
|
||||
import { compose } from 'ramda'
|
||||
import React, { Fragment } from 'react'
|
||||
import { Trans } from 'react-i18next'
|
||||
import { connect } from 'react-redux'
|
||||
import {
|
||||
analysisWithDefaultsSelector,
|
||||
parsedRulesSelector
|
||||
} from 'Selectors/analyseSelectors'
|
||||
import { analysisToCotisationsSelector } from 'Selectors/ficheDePaieSelectors'
|
||||
import './PaySlip.css'
|
||||
import { Line, SalaireBrutSection, SalaireNetSection } from './PaySlipSections'
|
||||
import RuleLink from './RuleLink'
|
||||
|
||||
type ConnectedPropTypes = ?FicheDePaie & {
|
||||
colours: { lightestColour: string }
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withColours,
|
||||
connect(state => ({
|
||||
cotisations: analysisToCotisationsSelector(state),
|
||||
analysis: analysisWithDefaultsSelector(state),
|
||||
parsedRules: parsedRulesSelector(state)
|
||||
}))
|
||||
)(
|
||||
({
|
||||
colours: { lightestColour },
|
||||
cotisations,
|
||||
analysis,
|
||||
parsedRules
|
||||
}: ConnectedPropTypes) => {
|
||||
let getRule = getRuleFromAnalysis(analysis)
|
||||
|
||||
const heuresSupplémentaires = getRule(
|
||||
'contrat salarié . temps de travail . heures supplémentaires'
|
||||
)
|
||||
return (
|
||||
<div
|
||||
className="payslip__container"
|
||||
css={`
|
||||
.value {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
padding-right: 0.2em;
|
||||
}
|
||||
`}
|
||||
>
|
||||
<div className="payslip__salarySection">
|
||||
<Line
|
||||
rule={getRule('contrat salarié . temps de travail')}
|
||||
unit="heures/mois"
|
||||
maximumFractionDigits={1}
|
||||
/>
|
||||
{heuresSupplémentaires?.nodeValue > 0 && (
|
||||
<Line
|
||||
rule={heuresSupplémentaires}
|
||||
unit="heures/mois"
|
||||
maximumFractionDigits={1}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<SalaireBrutSection getRule={getRule} />
|
||||
{/* Section cotisations */}
|
||||
<div className="payslip__cotisationsSection">
|
||||
<h4>
|
||||
<Trans>Cotisations sociales</Trans>
|
||||
</h4>
|
||||
<h4>
|
||||
<Trans>Part employeur</Trans>
|
||||
</h4>
|
||||
<h4>
|
||||
<Trans>Part salarié</Trans>
|
||||
</h4>
|
||||
{cotisations.map(([brancheDottedName, cotisationList]) => {
|
||||
let branche = findRuleByDottedName(parsedRules, brancheDottedName)
|
||||
return (
|
||||
<Fragment key={branche.dottedName}>
|
||||
<h5 className="payslip__cotisationTitle">
|
||||
<RuleLink {...branche} />
|
||||
</h5>
|
||||
{cotisationList.map(cotisation => (
|
||||
<Fragment key={cotisation.dottedName}>
|
||||
<RuleLink
|
||||
style={{ backgroundColor: lightestColour }}
|
||||
{...cotisation}
|
||||
/>
|
||||
<Value
|
||||
nilValueSymbol="—"
|
||||
unit="€"
|
||||
customCSS="background-color: var(--lightestColour)"
|
||||
>
|
||||
{cotisation.montant.partPatronale}
|
||||
</Value>
|
||||
<Value
|
||||
nilValueSymbol="—"
|
||||
unit="€"
|
||||
customCSS="background-color: var(--lightestColour)"
|
||||
>
|
||||
{cotisation.montant.partSalariale}
|
||||
</Value>
|
||||
</Fragment>
|
||||
))}
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
|
||||
{/* Total cotisation */}
|
||||
<div className="payslip__total">
|
||||
<Trans>Total des retenues</Trans>
|
||||
</div>
|
||||
<Value
|
||||
nilValueSymbol="—"
|
||||
{...getRule('contrat salarié . cotisations . patronales')}
|
||||
unit="€"
|
||||
className="payslip__total"
|
||||
/>
|
||||
<Value
|
||||
nilValueSymbol="—"
|
||||
{...getRule('contrat salarié . cotisations . salariales')}
|
||||
unit="€"
|
||||
className="payslip__total"
|
||||
/>
|
||||
{/* Salaire chargé */}
|
||||
<Line rule={getRule('contrat salarié . rémunération . total')} />
|
||||
<span />
|
||||
</div>
|
||||
{/* Section salaire net */}
|
||||
<SalaireNetSection getRule={getRule} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,122 @@
|
|||
import { ThemeColoursContext } from 'Components/utils/withColours'
|
||||
import Value from 'Components/Value'
|
||||
import { findRuleByDottedName, getRuleFromAnalysis } from 'Engine/rules'
|
||||
import React, { Fragment, useContext } from 'react'
|
||||
import { Trans } from 'react-i18next'
|
||||
import { useSelector } from 'react-redux'
|
||||
import {
|
||||
analysisWithDefaultsSelector,
|
||||
parsedRulesSelector
|
||||
} from 'Selectors/analyseSelectors'
|
||||
import { analysisToCotisationsSelector } from 'Selectors/ficheDePaieSelectors'
|
||||
import './PaySlip.css'
|
||||
import { Line, SalaireBrutSection, SalaireNetSection } from './PaySlipSections'
|
||||
import RuleLink from './RuleLink'
|
||||
|
||||
export default function PaySlip() {
|
||||
const { lightestColour } = useContext(ThemeColoursContext)
|
||||
const cotisations = useSelector(analysisToCotisationsSelector)
|
||||
const analysis = useSelector(analysisWithDefaultsSelector)
|
||||
const parsedRules = useSelector(parsedRulesSelector)
|
||||
let getRule = getRuleFromAnalysis(analysis)
|
||||
|
||||
const heuresSupplémentaires = getRule(
|
||||
'contrat salarié . temps de travail . heures supplémentaires'
|
||||
)
|
||||
return (
|
||||
<div
|
||||
className="payslip__container"
|
||||
css={`
|
||||
.value {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
padding-right: 0.2em;
|
||||
}
|
||||
`}
|
||||
>
|
||||
<div className="payslip__salarySection">
|
||||
<Line
|
||||
rule={getRule('contrat salarié . temps de travail')}
|
||||
unit="heures/mois"
|
||||
maximumFractionDigits={1}
|
||||
/>
|
||||
{heuresSupplémentaires?.nodeValue > 0 && (
|
||||
<Line
|
||||
rule={heuresSupplémentaires}
|
||||
unit="heures/mois"
|
||||
maximumFractionDigits={1}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<SalaireBrutSection getRule={getRule} />
|
||||
{/* Section cotisations */}
|
||||
<div className="payslip__cotisationsSection">
|
||||
<h4>
|
||||
<Trans>Cotisations sociales</Trans>
|
||||
</h4>
|
||||
<h4>
|
||||
<Trans>Part employeur</Trans>
|
||||
</h4>
|
||||
<h4>
|
||||
<Trans>Part salarié</Trans>
|
||||
</h4>
|
||||
{cotisations.map(([brancheDottedName, cotisationList]) => {
|
||||
let branche = findRuleByDottedName(parsedRules, brancheDottedName)
|
||||
return (
|
||||
<Fragment key={branche.dottedName}>
|
||||
<h5 className="payslip__cotisationTitle">
|
||||
<RuleLink {...branche} />
|
||||
</h5>
|
||||
{cotisationList.map(cotisation => (
|
||||
<Fragment key={cotisation.dottedName}>
|
||||
<RuleLink
|
||||
style={{ backgroundColor: lightestColour }}
|
||||
{...cotisation}
|
||||
/>
|
||||
<Value
|
||||
nilValueSymbol="—"
|
||||
unit="€"
|
||||
customCSS="background-color: var(--lightestColour)"
|
||||
>
|
||||
{cotisation.montant.partPatronale}
|
||||
</Value>
|
||||
<Value
|
||||
nilValueSymbol="—"
|
||||
unit="€"
|
||||
customCSS="background-color: var(--lightestColour)"
|
||||
>
|
||||
{cotisation.montant.partSalariale}
|
||||
</Value>
|
||||
</Fragment>
|
||||
))}
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
|
||||
{/* Total cotisation */}
|
||||
<div className="payslip__total">
|
||||
<Trans>Total des retenues</Trans>
|
||||
</div>
|
||||
<Value
|
||||
nilValueSymbol="—"
|
||||
{...getRule('contrat salarié . cotisations . patronales')}
|
||||
unit="€"
|
||||
className="payslip__total"
|
||||
/>
|
||||
<Value
|
||||
nilValueSymbol="—"
|
||||
{...getRule('contrat salarié . cotisations . salariales')}
|
||||
unit="€"
|
||||
className="payslip__total"
|
||||
/>
|
||||
{/* Salaire chargé */}
|
||||
<Line rule={getRule('contrat salarié . rémunération . total')} />
|
||||
<span />
|
||||
</div>
|
||||
{/* Section salaire net */}
|
||||
<SalaireNetSection getRule={getRule} />
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import { goToQuestion } from 'Actions/actions'
|
||||
import { T } from 'Components'
|
||||
import { compose, contains, filter, reject, toPairs } from 'ramda'
|
||||
import { contains, filter, pipe, reject, toPairs } from 'ramda'
|
||||
import React from 'react'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { RootState } from 'Reducers/rootReducer'
|
||||
|
@ -8,6 +8,7 @@ import {
|
|||
currentQuestionSelector,
|
||||
nextStepsSelector
|
||||
} from 'Selectors/analyseSelectors'
|
||||
import { DottedName } from 'Types/rule'
|
||||
|
||||
export default function QuickLinks() {
|
||||
const currentQuestion = useSelector(currentQuestionSelector)
|
||||
|
@ -23,11 +24,11 @@ export default function QuickLinks() {
|
|||
if (!quickLinks) {
|
||||
return null
|
||||
}
|
||||
const links = compose(
|
||||
toPairs,
|
||||
filter(dottedName => contains(dottedName, nextSteps)) as any,
|
||||
reject(dottedName => contains(dottedName, quickLinksToHide))
|
||||
)(quickLinks) as any
|
||||
const links = pipe(
|
||||
reject((dottedName: DottedName) => contains(dottedName, quickLinksToHide)),
|
||||
filter((dottedName: DottedName) => contains(dottedName, nextSteps)),
|
||||
toPairs
|
||||
)(quickLinks)
|
||||
|
||||
return (
|
||||
!!links.length && (
|
||||
|
|
|
@ -10,7 +10,7 @@ type RuleLinkProps = {
|
|||
dottedName: Rule['dottedName']
|
||||
title?: Rule['title']
|
||||
style?: React.CSSProperties
|
||||
children: React.ReactNode
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
export default function RuleLink({
|
||||
|
|
|
@ -39,7 +39,7 @@ export default function RulePage({ match }) {
|
|||
if (!findRuleByDottedName(flatRules, decodedRuleName))
|
||||
return <Redirect to="/404" />
|
||||
|
||||
return renderRule(decodedRuleName)
|
||||
return renderRule(decodedRuleName as DottedName)
|
||||
}
|
||||
|
||||
const BackToSimulation = connect(null, { goBackToSimulation })(
|
||||
|
|
|
@ -5,16 +5,23 @@ import React, { useContext, useEffect, useState } from 'react'
|
|||
import Highlighter from 'react-highlight-words'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Link, Redirect } from 'react-router-dom'
|
||||
import { Rule } from 'Types/rule'
|
||||
import Worker from 'worker-loader!./SearchBar.worker.js'
|
||||
import { capitalise0 } from '../utils'
|
||||
|
||||
const worker = new Worker()
|
||||
|
||||
type SearchBarProps = {
|
||||
rules: Array<Rule>
|
||||
showDefaultList: boolean
|
||||
finally?: () => void
|
||||
}
|
||||
|
||||
export default function SearchBar({
|
||||
rules,
|
||||
showDefaultList,
|
||||
finally: finallyCallback
|
||||
}) {
|
||||
}: SearchBarProps) {
|
||||
const sitePaths = useContext(SitePathsContext)
|
||||
const [input, setInput] = useState('')
|
||||
const [selectedOption, setSelectedOption] = useState(null)
|
||||
|
@ -31,7 +38,7 @@ export default function SearchBar({
|
|||
worker.onmessage = ({ data: results }) => setResults(results)
|
||||
}, [rules])
|
||||
|
||||
let renderOptions = rules => {
|
||||
let renderOptions = (rules?: Array<Rule>) => {
|
||||
let options =
|
||||
(rules && sortBy(rule => rule.dottedName, rules)) || take(5)(results)
|
||||
return <ul>{options.map(option => renderOption(option))}</ul>
|
||||
|
@ -57,7 +64,7 @@ export default function SearchBar({
|
|||
>
|
||||
<div
|
||||
style={{
|
||||
fontWeight: '300',
|
||||
fontWeight: 300,
|
||||
fontSize: '85%',
|
||||
lineHeight: '.9em'
|
||||
}}
|
|
@ -1,118 +0,0 @@
|
|||
import { goToQuestion, resetSimulation } from 'Actions/actions'
|
||||
import Overlay from 'Components/Overlay'
|
||||
import RuleLink from 'Components/RuleLink'
|
||||
import Value from 'Components/Value'
|
||||
import { getRuleFromAnalysis } from 'Engine/rules'
|
||||
import { compose } from 'ramda'
|
||||
import React from 'react'
|
||||
import emoji from 'react-easy-emoji'
|
||||
import { Trans } from 'react-i18next'
|
||||
import { connect } from 'react-redux'
|
||||
import { createSelector } from 'reselect'
|
||||
import {
|
||||
analysisWithDefaultsSelector,
|
||||
nextStepsSelector
|
||||
} from 'Selectors/analyseSelectors'
|
||||
import { softCatch } from '../../utils'
|
||||
import './AnswerList.css'
|
||||
|
||||
const AnswerList = ({
|
||||
folded,
|
||||
next,
|
||||
onClose,
|
||||
goToQuestion,
|
||||
resetSimulation
|
||||
}) => (
|
||||
<Overlay onClose={onClose} className="answer-list">
|
||||
<h2>
|
||||
{emoji('📋 ')}
|
||||
<Trans>Mes réponses</Trans>
|
||||
<small css="margin-left: 2em; img {font-size: .8em}">
|
||||
{emoji('🗑')}{' '}
|
||||
<button
|
||||
className="ui__ simple small button"
|
||||
onClick={() => {
|
||||
resetSimulation()
|
||||
onClose()
|
||||
}}>
|
||||
<Trans>Tout effacer</Trans>
|
||||
</button>
|
||||
</small>
|
||||
</h2>
|
||||
<StepsTable {...{ rules: folded, onClose, goToQuestion }} />
|
||||
<h2>
|
||||
{emoji('🔮 ')}
|
||||
<Trans>Prochaines questions</Trans>
|
||||
</h2>
|
||||
<StepsTable {...{ rules: next, onClose, goToQuestion }} />
|
||||
</Overlay>
|
||||
)
|
||||
|
||||
let StepsTable = ({ rules, onClose, goToQuestion }) => (
|
||||
<table>
|
||||
<tbody>
|
||||
{rules.map(rule => (
|
||||
<tr
|
||||
key={rule.dottedName}
|
||||
css={`
|
||||
background: var(--lightestColour);
|
||||
`}>
|
||||
<td>
|
||||
<RuleLink {...rule} />
|
||||
</td>
|
||||
<td>
|
||||
<button
|
||||
className="answer"
|
||||
css={`
|
||||
display: inline-block;
|
||||
padding: 0.6rem;
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
width: 100%;
|
||||
text-align: start;
|
||||
font-weight: 500;
|
||||
> span {
|
||||
border-bottom: 1px dashed blue;
|
||||
border-bottom-color: var(--textColourOnWhite);
|
||||
padding: 0.05em 0em;
|
||||
display: inline-block;
|
||||
}
|
||||
`}
|
||||
onClick={() => {
|
||||
goToQuestion(rule.dottedName)
|
||||
onClose()
|
||||
}}>
|
||||
<span className="answerContent">
|
||||
<Value {...rule} />
|
||||
</span>
|
||||
</button>{' '}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
)
|
||||
|
||||
const stepsToRules = createSelector(
|
||||
state => state.conversationSteps.foldedSteps,
|
||||
nextStepsSelector,
|
||||
analysisWithDefaultsSelector,
|
||||
(folded, nextSteps, analysis) => ({
|
||||
folded: folded
|
||||
.map(softCatch(getRuleFromAnalysis(analysis)))
|
||||
.filter(Boolean),
|
||||
next: nextSteps
|
||||
.map(softCatch(getRuleFromAnalysis(analysis)))
|
||||
.filter(Boolean)
|
||||
})
|
||||
)
|
||||
|
||||
export default compose(
|
||||
connect(
|
||||
state => stepsToRules(state),
|
||||
{
|
||||
resetSimulation,
|
||||
goToQuestion
|
||||
}
|
||||
)
|
||||
)(AnswerList)
|
|
@ -0,0 +1,112 @@
|
|||
import { goToQuestion, resetSimulation } from 'Actions/actions'
|
||||
import Overlay from 'Components/Overlay'
|
||||
import RuleLink from 'Components/RuleLink'
|
||||
import Value from 'Components/Value'
|
||||
import { getRuleFromAnalysis } from 'Engine/rules'
|
||||
import React from 'react'
|
||||
import emoji from 'react-easy-emoji'
|
||||
import { Trans } from 'react-i18next'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { RootState } from 'Reducers/rootReducer'
|
||||
import { createSelector } from 'reselect'
|
||||
import {
|
||||
analysisWithDefaultsSelector,
|
||||
nextStepsSelector
|
||||
} from 'Selectors/analyseSelectors'
|
||||
import { softCatch } from '../../utils'
|
||||
import './AnswerList.css'
|
||||
|
||||
export default function AnswerList({ onClose }) {
|
||||
const dispatch = useDispatch()
|
||||
const { folded, next } = useSelector(stepsToRules)
|
||||
return (
|
||||
<Overlay onClose={onClose} className="answer-list">
|
||||
<h2>
|
||||
{emoji('📋 ')}
|
||||
<Trans>Mes réponses</Trans>
|
||||
<small css="margin-left: 2em; img {font-size: .8em}">
|
||||
{emoji('🗑')}{' '}
|
||||
<button
|
||||
className="ui__ simple small button"
|
||||
onClick={() => {
|
||||
dispatch(resetSimulation())
|
||||
onClose()
|
||||
}}
|
||||
>
|
||||
<Trans>Tout effacer</Trans>
|
||||
</button>
|
||||
</small>
|
||||
</h2>
|
||||
<StepsTable {...{ rules: folded, onClose }} />
|
||||
<h2>
|
||||
{emoji('🔮 ')}
|
||||
<Trans>Prochaines questions</Trans>
|
||||
</h2>
|
||||
<StepsTable {...{ rules: next, onClose }} />
|
||||
</Overlay>
|
||||
)
|
||||
}
|
||||
|
||||
function StepsTable({ rules, onClose }) {
|
||||
const dispatch = useDispatch()
|
||||
return (
|
||||
<table>
|
||||
<tbody>
|
||||
{rules.map(rule => (
|
||||
<tr
|
||||
key={rule.dottedName}
|
||||
css={`
|
||||
background: var(--lightestColour);
|
||||
`}
|
||||
>
|
||||
<td>
|
||||
<RuleLink {...rule} />
|
||||
</td>
|
||||
<td>
|
||||
<button
|
||||
className="answer"
|
||||
css={`
|
||||
display: inline-block;
|
||||
padding: 0.6rem;
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
width: 100%;
|
||||
text-align: start;
|
||||
font-weight: 500;
|
||||
> span {
|
||||
border-bottom: 1px dashed blue;
|
||||
border-bottom-color: var(--textColourOnWhite);
|
||||
padding: 0.05em 0em;
|
||||
display: inline-block;
|
||||
}
|
||||
`}
|
||||
onClick={() => {
|
||||
dispatch(goToQuestion(rule.dottedName))
|
||||
onClose()
|
||||
}}
|
||||
>
|
||||
<span className="answerContent">
|
||||
<Value {...rule} />
|
||||
</span>
|
||||
</button>{' '}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
)
|
||||
}
|
||||
|
||||
const stepsToRules = createSelector(
|
||||
(state: RootState) => state.conversationSteps.foldedSteps,
|
||||
nextStepsSelector,
|
||||
analysisWithDefaultsSelector,
|
||||
(folded, nextSteps, analysis) => ({
|
||||
folded: folded
|
||||
.map(softCatch(getRuleFromAnalysis(analysis)))
|
||||
.filter(Boolean),
|
||||
next: nextSteps
|
||||
.map(softCatch(getRuleFromAnalysis(analysis)))
|
||||
.filter(Boolean)
|
||||
})
|
||||
)
|
|
@ -3,14 +3,21 @@ import React, { useState } from 'react'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { defaultUnitsSelector } from 'Selectors/analyseSelectors'
|
||||
import { convertUnit, parseUnit } from '../../engine/units'
|
||||
import { convertUnit, parseUnit, Unit } from '../../engine/units'
|
||||
|
||||
type InputSuggestionsProps = {
|
||||
suggestions: Record<string, number>
|
||||
onFirstClick: (val: number) => void
|
||||
onSecondClick?: (val: number) => void
|
||||
unit: Unit
|
||||
}
|
||||
|
||||
export default function InputSuggestions({
|
||||
suggestions,
|
||||
onSecondClick = x => x,
|
||||
onFirstClick,
|
||||
unit
|
||||
}) {
|
||||
}: InputSuggestionsProps) {
|
||||
const [suggestion, setSuggestion] = useState(null)
|
||||
const { t } = useTranslation()
|
||||
const defaultUnit = parseUnit(useSelector(defaultUnitsSelector)[0])
|
||||
|
|
|
@ -53,7 +53,7 @@ export let getNextSteps = missingVariablesByTarget => {
|
|||
missingByTotalScore
|
||||
),
|
||||
pairs = toPairs(missingByCompound),
|
||||
sortedPairs = sortWith([descend(byCount), descend(byScore)], pairs)
|
||||
sortedPairs = sortWith([descend(byCount), descend(byScore) as any], pairs)
|
||||
return map(head, sortedPairs)
|
||||
}
|
||||
|
|
@ -15,11 +15,16 @@ export default (rules, rule, parsedRules) => {
|
|||
|
||||
parsedRules[rule.dottedName] = 'being parsed'
|
||||
/*
|
||||
The parseRule function will traverse the tree of the `rule` and produce an AST, an object containing other objects containing other objects...
|
||||
Some of the attributes of the rule are dynamic, they need to be parsed. It is the case of `non applicable si`, `applicable si`, `formule`.
|
||||
These attributes' values themselves may have mechanism properties (e. g. `barème`) or inline expressions (e. g. `maVariable + 3`).
|
||||
These mechanisms or variables are in turn traversed by `parse()`. During this processing, 'evaluate' and'jsx' functions are attached to the objects of the AST. They will be evaluated during the evaluation phase, called "analyse".
|
||||
*/
|
||||
The parseRule function will traverse the tree of the `rule` and produce an
|
||||
AST, an object containing other objects containing other objects... Some of
|
||||
the attributes of the rule are dynamic, they need to be parsed. It is the
|
||||
case of `non applicable si`, `applicable si`, `formule`. These attributes'
|
||||
values themselves may have mechanism properties (e. g. `barème`) or inline
|
||||
expressions (e. g. `maVariable + 3`). These mechanisms or variables are in
|
||||
turn traversed by `parse()`. During this processing, 'evaluate' and'jsx'
|
||||
functions are attached to the objects of the AST. They will be evaluated
|
||||
during the evaluation phase, called "analyse".
|
||||
*/
|
||||
|
||||
let parentDependencies = findParentDependencies(rules, rule)
|
||||
|
||||
|
@ -84,7 +89,7 @@ export default (rules, rule, parsedRules) => {
|
|||
|
||||
let child = parse(rules, rule, parsedRules)(value)
|
||||
|
||||
let jsx = (nodeValue, explanation) => makeJsx(explanation)
|
||||
let jsx = (_nodeValue, explanation) => makeJsx(explanation)
|
||||
|
||||
return {
|
||||
evaluate,
|
||||
|
@ -96,7 +101,7 @@ export default (rules, rule, parsedRules) => {
|
|||
explanation: child
|
||||
}
|
||||
},
|
||||
contrôles: map(control => {
|
||||
contrôles: map((control: any) => {
|
||||
let testExpression = parse(rules, rule, parsedRules)(control.si)
|
||||
if (
|
||||
!testExpression.explanation &&
|
||||
|
@ -118,7 +123,9 @@ export default (rules, rule, parsedRules) => {
|
|||
})(root)
|
||||
|
||||
parsedRules[rule.dottedName] = {
|
||||
// Pas de propriété explanation et jsx ici car on est parti du (mauvais) principe que 'non applicable si' et 'formule' sont particuliers, alors qu'ils pourraient être rangé avec les autres mécanismes
|
||||
// Pas de propriété explanation et jsx ici car on est parti du (mauvais)
|
||||
// principe que 'non applicable si' et 'formule' sont particuliers, alors
|
||||
// qu'ils pourraient être rangé avec les autres mécanismes
|
||||
...parsedRoot,
|
||||
evaluate,
|
||||
parsed: true,
|
||||
|
@ -135,7 +142,7 @@ export default (rules, rule, parsedRules) => {
|
|||
const explanation = { ...node.explanation, isDisabledBy }
|
||||
return { ...node, explanation, nodeValue }
|
||||
},
|
||||
jsx: (nodeValue, { isDisabledBy }) => {
|
||||
jsx: (_nodeValue, { isDisabledBy }) => {
|
||||
return (
|
||||
isDisabledBy.length > 0 && (
|
||||
<>
|
||||
|
@ -183,6 +190,7 @@ let evolveCond = (name, rule, rules, parsedRules) => value => {
|
|||
classes="ruleProp mecanism cond"
|
||||
name={name}
|
||||
value={nodeValue}
|
||||
unit={undefined}
|
||||
child={
|
||||
explanation.category === 'variable' ? (
|
||||
<div className="node">{makeJsx(explanation)}</div>
|
|
@ -46,7 +46,7 @@ export let enrichRule = rule => {
|
|||
if (defaultUnit && unit) {
|
||||
warning(
|
||||
dottedName,
|
||||
"Le paramètre `unité` n'est plus contraignant que `unité par défaut`.",
|
||||
'Le paramètre `unité` est plus contraignant que `unité par défaut`.',
|
||||
'Si vous souhaitez que la valeur de votre variable soit toujours la même unité, gardez `unité`'
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { evaluateControls } from 'Engine/controls'
|
||||
import parseRule from 'Engine/parseRule'
|
||||
import { chain, path } from 'ramda'
|
||||
import { DottedName } from 'Types/rule'
|
||||
import { evaluateNode } from './evaluation'
|
||||
import { parseReference } from './parseReference'
|
||||
import {
|
||||
|
@ -8,7 +9,7 @@ import {
|
|||
findRule,
|
||||
findRuleByDottedName
|
||||
} from './rules'
|
||||
import { parseUnit } from './units'
|
||||
import { parseUnit, Unit } from './units'
|
||||
|
||||
/*
|
||||
Dans ce fichier, les règles YAML sont parsées.
|
||||
|
@ -47,14 +48,17 @@ par exemple ainsi : https://github.com/Engelberg/instaparse#transforming-the-tre
|
|||
*/
|
||||
|
||||
export let parseAll = flatRules => {
|
||||
/* First we parse each rule one by one. When a mechanism is encountered, it is recursively parsed. When a reference to a variable is encountered, a 'variable' node is created, we don't parse variables recursively. */
|
||||
/* First we parse each rule one by one. When a mechanism is encountered, it is
|
||||
recursively parsed. When a reference to a variable is encountered, a
|
||||
'variable' node is created, we don't parse variables recursively. */
|
||||
|
||||
let parsedRules = {}
|
||||
|
||||
/* A rule `A` can disable a rule `B` using the rule `rend non applicable: B` in the definition of `A`.
|
||||
We need to map these exonerations to be able to retreive them from `B` */
|
||||
let nonApplicableMapping = {}
|
||||
let replacedByMapping = {}
|
||||
/* A rule `A` can disable a rule `B` using the rule `rend non applicable: B`
|
||||
in the definition of `A`. We need to map these exonerations to be able to
|
||||
retreive them from `B` */
|
||||
let nonApplicableMapping: Record<string, any> = {}
|
||||
let replacedByMapping: Record<string, any> = {}
|
||||
flatRules.forEach(rule => {
|
||||
const parsed = parseRule(flatRules, rule, parsedRules)
|
||||
if (parsed['rend non applicable']) {
|
||||
|
@ -107,7 +111,7 @@ export let parseAll = flatRules => {
|
|||
|
||||
export let getTargets = (target, rules) => {
|
||||
let multiSimulation = path(['simulateur', 'objectifs'])(target)
|
||||
let targets = multiSimulation
|
||||
let targets = Array.isArray(multiSimulation)
|
||||
? // On a un simulateur qui définit une liste d'objectifs
|
||||
multiSimulation
|
||||
.map(n => disambiguateRuleReference(rules, target, n))
|
||||
|
@ -118,16 +122,23 @@ export let getTargets = (target, rules) => {
|
|||
return targets
|
||||
}
|
||||
|
||||
export let analyseMany = (
|
||||
parsedRules,
|
||||
targetNames,
|
||||
defaultUnits = []
|
||||
) => situationGate => {
|
||||
type CacheMeta = {
|
||||
contextRule: Array<string>
|
||||
defaultUnits: Array<Unit>
|
||||
inversionFail?: {
|
||||
given: string
|
||||
estimated: string
|
||||
}
|
||||
}
|
||||
|
||||
export let analyseMany = (parsedRules, targetNames, defaultUnits = []) => (
|
||||
situationGate: (name: DottedName) => any
|
||||
) => {
|
||||
// TODO: we should really make use of namespaces at this level, in particular
|
||||
// setRule in Rule.js needs to get smarter and pass dottedName
|
||||
defaultUnits = defaultUnits.map(parseUnit)
|
||||
let cache = {
|
||||
_meta: { contextRule: [], defaultUnits }
|
||||
_meta: { contextRule: [], defaultUnits } as CacheMeta
|
||||
}
|
||||
|
||||
let parsedTargets = targetNames.map(t => {
|
||||
|
@ -148,6 +159,8 @@ export let analyseMany = (
|
|||
return { targets, cache, controls }
|
||||
}
|
||||
|
||||
export type Analysis = ReturnType<ReturnType<typeof analyse>>
|
||||
|
||||
export let analyse = (parsedRules, target, defaultUnits = []) => {
|
||||
return analyseMany(parsedRules, [target], defaultUnits)
|
||||
}
|
|
@ -1,13 +1,14 @@
|
|||
import { Action } from 'Actions/actions'
|
||||
import { Analysis } from 'Engine/traverse'
|
||||
import { areUnitConvertible, convertUnit, parseUnit } from 'Engine/units'
|
||||
import {
|
||||
compose,
|
||||
defaultTo,
|
||||
dissoc,
|
||||
identity,
|
||||
lensPath,
|
||||
omit,
|
||||
over,
|
||||
pipe,
|
||||
set,
|
||||
uniq,
|
||||
without
|
||||
|
@ -18,7 +19,6 @@ import { analysisWithDefaultsSelector } from 'Selectors/analyseSelectors'
|
|||
import { SavedSimulation } from 'Selectors/storageSelectors'
|
||||
import { DottedName, Rule } from 'Types/rule'
|
||||
import i18n, { AvailableLangs } from '../i18n'
|
||||
import { Unit } from './../engine/units'
|
||||
import inFranceAppReducer from './inFranceAppReducer'
|
||||
import storageRootReducer from './storageReducer'
|
||||
|
||||
|
@ -180,7 +180,7 @@ export type Simulation = {
|
|||
function simulation(
|
||||
state: Simulation = null,
|
||||
action: Action,
|
||||
analysis: Record<DottedName, { nodeValue: any; unit: Unit | undefined }>
|
||||
analysis: Analysis | Array<Analysis>
|
||||
): Simulation | null {
|
||||
if (action.type === 'SET_SIMULATION') {
|
||||
const { config, url } = action
|
||||
|
@ -226,23 +226,27 @@ function simulation(
|
|||
return state
|
||||
}
|
||||
|
||||
const addAnswerToSituation = (dottedName: DottedName, value: any, state) => {
|
||||
return (compose(
|
||||
set(lensPath(['simulation', 'situation', dottedName]), value),
|
||||
const addAnswerToSituation = (
|
||||
dottedName: DottedName,
|
||||
value: unknown,
|
||||
state: RootState
|
||||
) => {
|
||||
return pipe(
|
||||
over(lensPath(['conversationSteps', 'foldedSteps']), (steps = []) =>
|
||||
uniq([...steps, dottedName])
|
||||
) as any
|
||||
) as any)(state)
|
||||
),
|
||||
set(lensPath(['simulation', 'situation', dottedName]), value)
|
||||
)(state)
|
||||
}
|
||||
|
||||
const removeAnswerFromSituation = (dottedName: DottedName, state) => {
|
||||
return (compose(
|
||||
over(lensPath(['simulation', 'situation']), dissoc(dottedName)),
|
||||
over(
|
||||
lensPath(['conversationSteps', 'foldedSteps']),
|
||||
without([dottedName])
|
||||
) as any
|
||||
) as any)(state)
|
||||
const removeAnswerFromSituation = (
|
||||
dottedName: DottedName,
|
||||
state: RootState
|
||||
) => {
|
||||
return pipe(
|
||||
over(lensPath(['conversationSteps', 'foldedSteps']), without([dottedName])),
|
||||
over(lensPath(['simulation', 'situation']), dissoc(dottedName))
|
||||
)(state)
|
||||
}
|
||||
|
||||
const existingCompanyRootReducer = (state: RootState, action) => {
|
||||
|
|
|
@ -86,7 +86,7 @@ export const useTarget = (dottedName: DottedName) => {
|
|||
return targets && targets.find(t => t.dottedName === dottedName)
|
||||
}
|
||||
|
||||
export let noUserInputSelector = state =>
|
||||
export let noUserInputSelector = (state: RootState) =>
|
||||
!Object.keys(situationSelector(state)).length
|
||||
|
||||
export let firstStepCompletedSelector = createSelector(
|
||||
|
@ -221,7 +221,7 @@ export let exampleAnalysisSelector = createSelector(
|
|||
analyseRule(
|
||||
rules,
|
||||
dottedName,
|
||||
dottedName => situation[dottedName],
|
||||
(dottedName: DottedName) => situation[dottedName],
|
||||
example.defaultUnits
|
||||
)
|
||||
)
|
||||
|
@ -234,18 +234,19 @@ let makeAnalysisSelector = (situationSelector: SituationSelectorType) =>
|
|||
situationSelector,
|
||||
defaultUnitsSelector
|
||||
],
|
||||
(parsedRules, targetNames, situations, defaultUnits) =>
|
||||
mapOrApply(
|
||||
(parsedRules, targetNames, situations, defaultUnits) => {
|
||||
return mapOrApply(
|
||||
situation =>
|
||||
analyseMany(
|
||||
parsedRules,
|
||||
targetNames,
|
||||
defaultUnits
|
||||
)(dottedName => {
|
||||
)((dottedName: DottedName) => {
|
||||
return situation[dottedName]
|
||||
}),
|
||||
situations
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
export let analysisWithDefaultsSelector = makeAnalysisSelector(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* @flow */
|
||||
import { Analysis } from 'Engine/traverse'
|
||||
import {
|
||||
add,
|
||||
concat,
|
||||
|
@ -16,10 +16,20 @@ import {
|
|||
} from 'ramda'
|
||||
import { createSelector } from 'reselect'
|
||||
import { analysisWithDefaultsSelector } from 'Selectors/analyseSelectors'
|
||||
import { Branch, Cotisation } from './repartitionSelectors'
|
||||
// Used for type consistency
|
||||
export const BLANK_COTISATION: Cotisation = {
|
||||
montant: {
|
||||
partPatronale: 0,
|
||||
partSalariale: 0
|
||||
},
|
||||
unit: 'ERROR_SHOULD_BE_INSTANCIATED',
|
||||
dottedName: 'ERROR_SHOULD_BE_INSTANCIATED' as any,
|
||||
title: 'ERROR_SHOULD_BE_INSTANCIATED',
|
||||
branche: 'protection sociale . autres'
|
||||
}
|
||||
|
||||
// These functions help build the payslip. They take the cotisations from the cache, braving all the particularities of the current engine's implementation, handles the part patronale and part salariale, and gives a map by branch.
|
||||
|
||||
export const COTISATION_BRANCHE_ORDER: Array<Branche> = [
|
||||
export const COTISATION_BRANCHE_ORDER: Array<Branch> = [
|
||||
'protection sociale . santé',
|
||||
'protection sociale . accidents du travail et maladies professionnelles',
|
||||
'protection sociale . retraite',
|
||||
|
@ -30,50 +40,34 @@ export const COTISATION_BRANCHE_ORDER: Array<Branche> = [
|
|||
'protection sociale . autres'
|
||||
]
|
||||
|
||||
// Used for type consistency
|
||||
export const BLANK_COTISATION: Cotisation = {
|
||||
montant: {
|
||||
partPatronale: 0,
|
||||
partSalariale: 0
|
||||
},
|
||||
dottedName: 'ERROR_SHOULD_BE_INSTANCIATED',
|
||||
title: 'ERROR_SHOULD_BE_INSTANCIATED',
|
||||
branche: 'protection sociale . autres'
|
||||
}
|
||||
|
||||
function duParSelector(
|
||||
variable: VariableWithCotisation
|
||||
): ?('employeur' | 'employé') {
|
||||
function duParSelector(variable): 'employeur' | 'salarié' {
|
||||
const dusPar = [
|
||||
['cotisation', 'dû par'],
|
||||
['taxe', 'dû par'],
|
||||
['explanation', 'cotisation', 'dû par'],
|
||||
['explanation', 'taxe', 'dû par']
|
||||
].map(p => path(p, variable))
|
||||
return dusPar.filter(Boolean)[0]
|
||||
return dusPar.filter(Boolean)[0] as any
|
||||
}
|
||||
function brancheSelector(variable: VariableWithCotisation): Branche {
|
||||
function brancheSelector(variable): Branch {
|
||||
const branches = [
|
||||
['cotisation', 'branche'],
|
||||
['taxe', 'branche'],
|
||||
['explanation', 'cotisation', 'branche'],
|
||||
['explanation', 'taxe', 'branche']
|
||||
].map(p => path(p, variable))
|
||||
return (
|
||||
// $FlowFixMe
|
||||
'protection sociale . ' + (branches.filter(Boolean)[0] || 'autres')
|
||||
)
|
||||
return ('protection sociale . ' +
|
||||
(branches.filter(Boolean)[0] || 'autres')) as any
|
||||
}
|
||||
|
||||
// $FlowFixMe
|
||||
export const mergeCotisations: (
|
||||
Cotisation,
|
||||
Cotisation
|
||||
a: Cotisation,
|
||||
b: Cotisation
|
||||
) => Cotisation = mergeWithKey((key, a, b) =>
|
||||
key === 'montant' ? mergeWith(add, a, b) : b
|
||||
)
|
||||
|
||||
const variableToCotisation = (variable: VariableWithCotisation): Cotisation => {
|
||||
const variableToCotisation = (variable): Cotisation => {
|
||||
return mergeCotisations(BLANK_COTISATION, {
|
||||
...variable.explanation,
|
||||
branche: brancheSelector(variable),
|
||||
|
@ -84,7 +78,7 @@ const variableToCotisation = (variable: VariableWithCotisation): Cotisation => {
|
|||
}
|
||||
})
|
||||
}
|
||||
const groupByBranche = (cotisations: Array<Cotisation>): Cotisations => {
|
||||
const groupByBranche = (cotisations: Array<Cotisation>) => {
|
||||
const cotisationsMap = cotisations.reduce(
|
||||
(acc, cotisation) => ({
|
||||
...acc,
|
||||
|
@ -94,11 +88,10 @@ const groupByBranche = (cotisations: Array<Cotisation>): Cotisations => {
|
|||
)
|
||||
return COTISATION_BRANCHE_ORDER.map(branche => [
|
||||
branche,
|
||||
// $FlowFixMe
|
||||
cotisationsMap[branche]
|
||||
])
|
||||
}
|
||||
export let analysisToCotisations = analysis => {
|
||||
export let analysisToCotisations = (analysis: Analysis) => {
|
||||
const variables = [
|
||||
'contrat salarié . cotisations . salariales',
|
||||
'contrat salarié . cotisations . patronales'
|
||||
|
@ -108,7 +101,7 @@ export let analysisToCotisations = analysis => {
|
|||
.reduce(concat, [])
|
||||
|
||||
const cotisations = pipe(
|
||||
map(rule =>
|
||||
map((rule: any) =>
|
||||
// Following : weird logic to automatically handle negative negated value in sum
|
||||
|
||||
rule.operationType === 'calculation' &&
|
|
@ -1,5 +1,3 @@
|
|||
/* @flow */
|
||||
|
||||
import { getRuleFromAnalysis } from 'Engine/rules'
|
||||
import {
|
||||
add,
|
||||
|
@ -20,25 +18,39 @@ import {
|
|||
} from 'ramda'
|
||||
import { createSelector } from 'reselect'
|
||||
import { analysisWithDefaultsSelector } from 'Selectors/analyseSelectors'
|
||||
import { Rule } from 'Types/rule'
|
||||
import {
|
||||
analysisToCotisations,
|
||||
BLANK_COTISATION,
|
||||
mergeCotisations
|
||||
} from './ficheDePaieSelectors'
|
||||
|
||||
import type {
|
||||
Cotisation,
|
||||
MontantPartagé,
|
||||
Branche,
|
||||
Répartition
|
||||
} from 'Types/ResultViewTypes'
|
||||
export type Cotisation = Rule & {
|
||||
branche: Branch
|
||||
montant: MontantPartagé
|
||||
}
|
||||
|
||||
type MontantPartagé = {
|
||||
partSalariale: number
|
||||
partPatronale: number
|
||||
}
|
||||
|
||||
export type Branch =
|
||||
| 'protection sociale . santé'
|
||||
| 'protection sociale . accidents du travail et maladies professionnelles'
|
||||
| 'protection sociale . retraite'
|
||||
| 'protection sociale . famille'
|
||||
| 'protection sociale . assurance chômage'
|
||||
| 'protection sociale . formation'
|
||||
| 'protection sociale . transport'
|
||||
| 'protection sociale . autres'
|
||||
|
||||
const totalCotisations = (cotisations: Array<Cotisation>): MontantPartagé =>
|
||||
cotisations.reduce(mergeCotisations, BLANK_COTISATION).montant
|
||||
|
||||
const byMontantTotal = (
|
||||
a: [Branche, MontantPartagé],
|
||||
b: [Branche, MontantPartagé]
|
||||
a: [Branch, MontantPartagé],
|
||||
b: [Branch, MontantPartagé]
|
||||
): number => {
|
||||
return (
|
||||
b[1].partPatronale +
|
||||
|
@ -48,7 +60,7 @@ const byMontantTotal = (
|
|||
)
|
||||
}
|
||||
|
||||
const REPARTITION_CSG: { [Branche]: number } = {
|
||||
const REPARTITION_CSG: Partial<Record<Branch, number>> = {
|
||||
'protection sociale . famille': 0.85,
|
||||
'protection sociale . santé': 7.75,
|
||||
// TODO: cette part correspond à l'amortissement de la dette de la sécurité sociale.
|
||||
|
@ -57,10 +69,9 @@ const REPARTITION_CSG: { [Branche]: number } = {
|
|||
}
|
||||
function applyCSGInPlace(
|
||||
CSG: Cotisation,
|
||||
rawRépartition: { [Branche]: MontantPartagé }
|
||||
rawRépartition: Record<Branch, MontantPartagé>
|
||||
): void {
|
||||
// $FlowFixMe
|
||||
for (const branche: Branche in REPARTITION_CSG) {
|
||||
for (const branche in REPARTITION_CSG) {
|
||||
rawRépartition[branche] = {
|
||||
partPatronale:
|
||||
rawRépartition[branche].partPatronale +
|
||||
|
@ -82,15 +93,14 @@ const brancheConcernéeParLaRéduction = [
|
|||
].map(branche => 'protection sociale . ' + branche)
|
||||
function applyReduction(
|
||||
réduction,
|
||||
répartitionMap: { [Branche]: MontantPartagé }
|
||||
): { [Branche]: MontantPartagé } {
|
||||
const totalPatronal = pipe(
|
||||
répartitionMap: Record<Branch, MontantPartagé>
|
||||
): Record<Branch, MontantPartagé> {
|
||||
const totalPatronal = (pipe(
|
||||
pick(brancheConcernéeParLaRéduction),
|
||||
Object.values,
|
||||
|
||||
reduce(mergeWith(add), {})
|
||||
// $FlowFixMe
|
||||
)(répartitionMap).partPatronale
|
||||
)(répartitionMap) as any).partPatronale
|
||||
return mapObjIndexed(
|
||||
({ partPatronale, partSalariale }, branche) => ({
|
||||
partPatronale: brancheConcernéeParLaRéduction.find(equals(branche))
|
||||
|
@ -98,16 +108,12 @@ function applyReduction(
|
|||
: partPatronale,
|
||||
partSalariale
|
||||
}),
|
||||
// $FlowFixMe
|
||||
répartitionMap
|
||||
)
|
||||
}
|
||||
|
||||
const répartition = (analysis): ?Répartition => {
|
||||
// $FlowFixMe
|
||||
let cotisations: { [Branche]: Array<Cotisation> } = fromPairs(
|
||||
analysisToCotisations(analysis)
|
||||
)
|
||||
const répartition = analysis => {
|
||||
let cotisations = fromPairs(analysisToCotisations(analysis) as any)
|
||||
|
||||
const getRule = getRuleFromAnalysis(analysis),
|
||||
salaireNet = getRule('contrat salarié . rémunération . net'),
|
||||
|
@ -117,7 +123,7 @@ const répartition = (analysis): ?Répartition => {
|
|||
'contrat salarié . cotisations . patronales . réductions de cotisations'
|
||||
)
|
||||
let CSG
|
||||
const autresCotisations = cotisations['protection sociale . autres']
|
||||
const autresCotisations = cotisations['protection sociale . autres'] as any
|
||||
if (autresCotisations) {
|
||||
CSG = autresCotisations.find(propEq('dottedName', 'contrat salarié . CSG'))
|
||||
cotisations['protection sociale . autres'] = without(
|
||||
|
@ -126,39 +132,34 @@ const répartition = (analysis): ?Répartition => {
|
|||
)
|
||||
}
|
||||
|
||||
// $FlowFixMe
|
||||
let répartitionMap: { [Branche]: MontantPartagé } = map(
|
||||
totalCotisations,
|
||||
cotisations
|
||||
)
|
||||
let répartitionMap = map(totalCotisations, cotisations) as Record<
|
||||
Branch,
|
||||
MontantPartagé
|
||||
>
|
||||
if (CSG) {
|
||||
applyCSGInPlace(CSG, répartitionMap)
|
||||
}
|
||||
|
||||
répartitionMap = applyReduction(réductionsDeCotisations, répartitionMap)
|
||||
return {
|
||||
// $FlowFixMe
|
||||
répartition: compose(
|
||||
sort(byMontantTotal),
|
||||
Object.entries,
|
||||
Object.entries as any,
|
||||
filter(
|
||||
({ partPatronale, partSalariale }) =>
|
||||
Math.round(partPatronale + partSalariale) !== 0
|
||||
)
|
||||
)(répartitionMap),
|
||||
// $FlowFixMe
|
||||
total: cotisationsRule.nodeValue,
|
||||
cotisations: cotisationsRule,
|
||||
maximum: compose(
|
||||
reduce(max, 0),
|
||||
map(montant => montant.partPatronale + montant.partSalariale),
|
||||
Object.values
|
||||
// $FlowFixMe
|
||||
)(répartitionMap),
|
||||
salaireNet,
|
||||
salaireChargé
|
||||
}
|
||||
}
|
||||
|
||||
// $FlowFixMe
|
||||
export default createSelector([analysisWithDefaultsSelector], répartition)
|
|
@ -1,10 +1,9 @@
|
|||
|
||||
import type { Store } from 'redux'
|
||||
import { Action } from 'Actions/actions'
|
||||
import { omit } from 'ramda'
|
||||
import { RootState } from 'Reducers/rootReducer'
|
||||
import { Store } from 'redux'
|
||||
import { debounce } from '../utils'
|
||||
import safeLocalStorage from './safeLocalStorage'
|
||||
import type { State } from 'Types/State'
|
||||
import type { Action } from 'Types/ActionsTypes'
|
||||
|
||||
const VERSION = 3
|
||||
|
||||
|
@ -13,8 +12,8 @@ const LOCAL_STORAGE_KEY = 'mycompanyinfrance::persisted-everything:v' + VERSION
|
|||
type OptionsType = {
|
||||
except?: Array<string>
|
||||
}
|
||||
export const persistEverything = (options?: OptionsType = {}) => (
|
||||
store: Store<State, Action>
|
||||
export const persistEverything = (options: OptionsType = {}) => (
|
||||
store: Store<RootState, Action>
|
||||
): void => {
|
||||
const listener = () => {
|
||||
const state = store.getState()
|
||||
|
@ -26,7 +25,7 @@ export const persistEverything = (options?: OptionsType = {}) => (
|
|||
store.subscribe(debounce(1000, listener))
|
||||
}
|
||||
|
||||
export function retrievePersistedState(): ?State {
|
||||
export function retrievePersistedState(): RootState {
|
||||
const serializedState = safeLocalStorage.getItem(LOCAL_STORAGE_KEY)
|
||||
return serializedState ? JSON.parse(serializedState) : null
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
|
||||
import type { Store } from 'redux'
|
||||
import { Action } from 'Actions/actions'
|
||||
import { RootState } from 'Reducers/rootReducer'
|
||||
import { Store } from 'redux'
|
||||
import { SavedSimulation } from 'Selectors/storageSelectors'
|
||||
import { debounce } from '../utils'
|
||||
import safeLocalStorage from './safeLocalStorage'
|
||||
import { deserialize, serialize } from './serializeSimulation'
|
||||
import type { State, SavedSimulation } from '../types/State'
|
||||
import type { Action } from 'Types/ActionsTypes'
|
||||
|
||||
const VERSION = 3
|
||||
|
||||
const LOCAL_STORAGE_KEY = 'embauche.gouv.fr::persisted-simulation::v' + VERSION
|
||||
|
||||
export function persistSimulation(store: Store<State, Action>) {
|
||||
export function persistSimulation(store: Store<RootState, Action>) {
|
||||
const listener = () => {
|
||||
const state = store.getState()
|
||||
if (!state.conversationSteps.foldedSteps.length) {
|
||||
|
@ -21,7 +21,7 @@ export function persistSimulation(store: Store<State, Action>) {
|
|||
store.subscribe(debounce(1000, listener))
|
||||
}
|
||||
|
||||
export function retrievePersistedSimulation(): ?SavedSimulation {
|
||||
export function retrievePersistedSimulation(): SavedSimulation {
|
||||
const serializedState = safeLocalStorage.getItem(LOCAL_STORAGE_KEY)
|
||||
return serializedState ? deserialize(serializedState) : null
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
export default {
|
||||
removeItem: function (...args) {
|
||||
removeItem: function (key: string) {
|
||||
try {
|
||||
return window.localStorage.removeItem(...args)
|
||||
return window.localStorage.removeItem(key)
|
||||
} catch (error) {
|
||||
if (error.name === 'SecurityError') {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
'[localStorage] Unable to remove item due to security settings'
|
||||
)
|
||||
|
@ -11,11 +12,12 @@ export default {
|
|||
return null
|
||||
}
|
||||
},
|
||||
getItem: function (...args) {
|
||||
getItem: function (key: string) {
|
||||
try {
|
||||
return window.localStorage.getItem(...args)
|
||||
return window.localStorage.getItem(key)
|
||||
} catch (error) {
|
||||
if (error.name === 'SecurityError') {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
'[localStorage] Unable to get item due to security settings'
|
||||
)
|
||||
|
@ -23,11 +25,12 @@ export default {
|
|||
return null
|
||||
}
|
||||
},
|
||||
setItem: function (...args) {
|
||||
setItem: function (key: string, value: string) {
|
||||
try {
|
||||
return window.localStorage.setItem(...args)
|
||||
return window.localStorage.setItem(key, value)
|
||||
} catch (error) {
|
||||
if (error.name === 'SecurityError') {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
'[localStorage] Unable to set item due to security settings'
|
||||
)
|
|
@ -1,10 +0,0 @@
|
|||
import type { State, SavedSimulation } from '../types/State.js'
|
||||
import { pipe } from 'ramda'
|
||||
import { currentSimulationSelector } from 'Selectors/storageSelectors'
|
||||
|
||||
export const serialize: State => string = pipe(
|
||||
currentSimulationSelector,
|
||||
JSON.stringify
|
||||
)
|
||||
|
||||
export const deserialize: string => SavedSimulation = JSON.parse
|
|
@ -0,0 +1,9 @@
|
|||
import { pipe } from 'ramda'
|
||||
import { currentSimulationSelector } from 'Selectors/storageSelectors'
|
||||
|
||||
export const serialize = pipe(
|
||||
currentSimulationSelector,
|
||||
JSON.stringify
|
||||
)
|
||||
|
||||
export const deserialize = JSON.parse
|
|
@ -1,68 +0,0 @@
|
|||
import type { RègleAvecMontant, Règle } from './RegleTypes'
|
||||
|
||||
export type Cotisation = Règle & {
|
||||
branche: Branche,
|
||||
montant: MontantPartagé
|
||||
}
|
||||
|
||||
export type Branche =
|
||||
| 'protection sociale . santé'
|
||||
| 'protection sociale . accidents du travail et maladies professionnelles'
|
||||
| 'protection sociale . retraite'
|
||||
| 'protection sociale . famille'
|
||||
| 'protection sociale . assurance chômage'
|
||||
| 'protection sociale . formation'
|
||||
| 'protection sociale . transport'
|
||||
| 'protection sociale . autres'
|
||||
|
||||
export type MontantPartagé = {
|
||||
partSalariale: number,
|
||||
partPatronale: number
|
||||
}
|
||||
export type Cotisations = Array<[Règle, Array<Cotisation>]>
|
||||
|
||||
export type VariableWithCotisation = {
|
||||
category: 'variable',
|
||||
name: string,
|
||||
title: string,
|
||||
cotisation: {|
|
||||
'dû par'?: 'salarié' | 'employeur',
|
||||
branche?: Branche
|
||||
|},
|
||||
dottedName: string,
|
||||
nodeValue: number,
|
||||
explanation: {
|
||||
cotisation: {
|
||||
'dû par'?: 'salarié' | 'employeur',
|
||||
branche?: Branche
|
||||
},
|
||||
taxe: {
|
||||
'dû par'?: 'salarié' | 'employeur',
|
||||
branche?: Branche
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type FicheDePaie = {
|
||||
salaireBrut: RègleAvecMontant,
|
||||
avantagesEnNature: RègleAvecMontant,
|
||||
indemnitésSalarié: RègleAvecMontant,
|
||||
salaireDeBase: RègleAvecMontant,
|
||||
// TODO supprimer (cf https://github.com/betagouv/syso/issues/242)
|
||||
réductionsDeCotisations: RègleAvecMontant,
|
||||
cotisations: Cotisations,
|
||||
totalCotisations: MontantPartagé,
|
||||
salaireChargé: RègleAvecMontant,
|
||||
salaireNetDeCotisations: RègleAvecMontant,
|
||||
rémunérationNetteImposable: RègleAvecMontant,
|
||||
salaireNet: RègleAvecMontant,
|
||||
nombreHeuresTravaillées: number
|
||||
}
|
||||
|
||||
export type Répartition = {
|
||||
répartition: Array<[Règle, MontantPartagé]>,
|
||||
total: MontantPartagé,
|
||||
salaireNet: RègleAvecMontant,
|
||||
salaireChargé: RègleAvecMontant,
|
||||
cotisationMaximum: number
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
declare module "worker-loader*" {
|
||||
class WebpackWorker extends Worker {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export = WebpackWorker;
|
||||
}
|
|
@ -3,8 +3,8 @@ export let capitalise0 = (name: string): string =>
|
|||
|
||||
export function debounce<ArgType>(
|
||||
timeout: number,
|
||||
fn: (arg: ArgType) => void
|
||||
): (arg: ArgType) => void {
|
||||
fn: (arg?: ArgType) => void
|
||||
): (arg?: ArgType) => void {
|
||||
let timeoutId: ReturnType<typeof setTimeout>
|
||||
return (...args) => {
|
||||
clearTimeout(timeoutId)
|
||||
|
@ -43,10 +43,10 @@ export function softCatch<ArgType, ReturnType>(
|
|||
}
|
||||
}
|
||||
}
|
||||
export function mapOrApply<A, B>(
|
||||
fn: (a: A) => B,
|
||||
x: Array<A> | A
|
||||
): Array<B> | B {
|
||||
|
||||
export function mapOrApply<A, B>(fn: (a: A) => B, x: A): B
|
||||
export function mapOrApply<A, B>(fn: (a: A) => B, x: Array<A>): Array<B>
|
||||
export function mapOrApply(fn, x) {
|
||||
return Array.isArray(x) ? x.map(fn) : fn(x)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { expect } from 'chai'
|
||||
// $FlowFixMe
|
||||
import salariéConfig from 'Components/simulationConfigs/salarié.yaml'
|
||||
import { getRuleFromAnalysis, rules } from 'Engine/rules'
|
||||
import { analysisWithDefaultsSelector } from 'Selectors/analyseSelectors'
|
||||
|
@ -27,20 +26,17 @@ let cotisations = null,
|
|||
|
||||
describe('pay slip selector', function() {
|
||||
beforeEach(() => {
|
||||
// $FlowFixMe
|
||||
cotisations = analysisToCotisationsSelector(state)
|
||||
analysis = analysisWithDefaultsSelector(state)
|
||||
|
||||
expect(cotisations).not.to.eq(null)
|
||||
})
|
||||
it('should have cotisations grouped by branches in the proper ordering', function() {
|
||||
// $FlowFixMe
|
||||
let branches = cotisations.map(([branche]) => branche)
|
||||
expect(branches).to.eql(COTISATION_BRANCHE_ORDER)
|
||||
})
|
||||
|
||||
it('should collect all cotisations in a branche', function() {
|
||||
// $FlowFixMe
|
||||
let cotisationsSanté = (cotisations.find(([branche]) =>
|
||||
branche.includes('santé')
|
||||
) || [])[1].map(cotisation => cotisation.name)
|
||||
|
@ -61,7 +57,6 @@ describe('pay slip selector', function() {
|
|||
})
|
||||
|
||||
it('should have value for "salarié" and "employeur" for a cotisation', function() {
|
||||
// $FlowFixMe
|
||||
let cotisationATMP = (cotisations.find(([branche]) =>
|
||||
branche.includes('accidents du travail et maladies professionnelles')
|
||||
) || [])[1][0]
|
||||
|
|
|
@ -10,6 +10,14 @@
|
|||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"allowJs": true,
|
||||
// The end goal is to enable `"strict": true` which correspond to the
|
||||
// following settings: noImplicitAny, noImplicitThis, alwaysStrict,
|
||||
// strictBindCallApply, strictNullChecks, strictFunctionTypes, and
|
||||
// strictPropertyInitialization. During the transition we enable these
|
||||
// settings one by one.
|
||||
"noImplicitThis": true,
|
||||
"strictBindCallApply": true,
|
||||
"paths": {
|
||||
"Actions/*": ["actions/*"],
|
||||
"Components": ["components"],
|
||||
|
|
30
yarn.lock
30
yarn.lock
|
@ -390,13 +390,6 @@
|
|||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
|
||||
"@babel/plugin-syntax-flow@^7.2.0":
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.2.0.tgz#a765f061f803bc48f240c26f8747faf97c26bf7c"
|
||||
integrity sha512-r6YMuZDWLtLlu0kqIim5o/3TNRAlWb073HwT3e2nKf9I8IIvOggPrnILYPsrrKilmn/mYEMCf/Z07w3yQJF6dg==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
|
||||
"@babel/plugin-syntax-json-strings@^7.2.0":
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470"
|
||||
|
@ -529,14 +522,6 @@
|
|||
"@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0"
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
|
||||
"@babel/plugin-transform-flow-strip-types@^7.0.0":
|
||||
version "7.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.4.4.tgz#d267a081f49a8705fc9146de0768c6b58dccd8f7"
|
||||
integrity sha512-WyVedfeEIILYEaWGAUWzVNyqG4sfsNooMhXWsu/YzOvVGcsnPb5PguysjJqI3t3qiaYj0BR8T2f5njdjTGe44Q==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/plugin-syntax-flow" "^7.2.0"
|
||||
|
||||
"@babel/plugin-transform-for-of@^7.4.4":
|
||||
version "7.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz#0267fc735e24c808ba173866c6c4d1440fc3c556"
|
||||
|
@ -805,14 +790,6 @@
|
|||
js-levenshtein "^1.1.3"
|
||||
semver "^5.5.0"
|
||||
|
||||
"@babel/preset-flow@^7.0.0-beta.51":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.0.0.tgz#afd764835d9535ec63d8c7d4caf1c06457263da2"
|
||||
integrity sha512-bJOHrYOPqJZCkPVbG1Lot2r5OSsB+iUOaxiHdlOeB1yPWS6evswVHwvkDLZ54WTaTRIk89ds0iHmGZSnxlPejQ==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/plugin-transform-flow-strip-types" "^7.0.0"
|
||||
|
||||
"@babel/preset-react@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.0.0.tgz#e86b4b3d99433c7b3e9e91747e2653958bc6b3c0"
|
||||
|
@ -1383,6 +1360,13 @@
|
|||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-highlight-words@^0.16.0":
|
||||
version "0.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-highlight-words/-/react-highlight-words-0.16.0.tgz#bcd67e9724fb5f070c955732f604068de5cbe30b"
|
||||
integrity sha512-bSVlhM5OXLO67UZD/orsoT1lS5p7w8ffoDis3TtU1mqmXW7epHHt4kB7QmmZzwXjgzRm++yOo6Xpp7PhRFBpXA==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-native@*":
|
||||
version "0.60.21"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.60.21.tgz#81a41cae7b232f52ab3983d854f4a0b0df79531e"
|
||||
|
|
Loading…
Reference in New Issue