Ajout des types null et undefined
Ajout des paramètres strictNullChecks et strictPropertyInitialization dans la configuration TypeScript et correction des environ 70 erreurs de typage résultantes.pull/817/head
parent
d89833502b
commit
ca5b7cc2df
|
@ -95,9 +95,10 @@ export default class Provider extends PureComponent<ProviderProps> {
|
|||
this.props.tracker.disconnectFromHistory()
|
||||
}
|
||||
render() {
|
||||
const iframeCouleur = new URLSearchParams(
|
||||
document?.location.search.substring(1)
|
||||
).get('couleur')
|
||||
const iframeCouleur =
|
||||
new URLSearchParams(document?.location.search.substring(1)).get(
|
||||
'couleur'
|
||||
) ?? undefined
|
||||
return (
|
||||
// If IE < 11 display nothing
|
||||
<ReduxProvider store={this.store}>
|
||||
|
|
|
@ -12,8 +12,8 @@ type PushType = (args: PushArgs) => void
|
|||
|
||||
export default class Tracker {
|
||||
push: PushType
|
||||
unlistenFromHistory: () => void
|
||||
previousPath: string
|
||||
unlistenFromHistory: (() => void) | undefined
|
||||
previousPath: string | undefined
|
||||
|
||||
constructor(pushFunction: PushType = args => window._paq.push(args)) {
|
||||
if (typeof window !== 'undefined') window._paq = window._paq || []
|
||||
|
|
|
@ -43,12 +43,17 @@ type DeletePreviousSimulationAction = {
|
|||
type: 'DELETE_PREVIOUS_SIMULATION'
|
||||
}
|
||||
|
||||
type SetExempleAction = {
|
||||
type: 'SET_EXAMPLE'
|
||||
name: null | string
|
||||
situation?: object
|
||||
dottedName?: string
|
||||
}
|
||||
type SetExempleAction =
|
||||
| {
|
||||
type: 'SET_EXAMPLE'
|
||||
name: null
|
||||
}
|
||||
| {
|
||||
type: 'SET_EXAMPLE'
|
||||
name: string
|
||||
situation: object
|
||||
dottedName: DottedName
|
||||
}
|
||||
|
||||
type ResetSimulationAction = ReturnType<typeof resetSimulation>
|
||||
type UpdateAction = ReturnType<typeof updateSituation>
|
||||
|
@ -142,7 +147,8 @@ export const goBackToSimulation = (): ThunkResult<void> => (
|
|||
{ history }
|
||||
) => {
|
||||
dispatch({ type: 'SET_EXAMPLE', name: null })
|
||||
history.push(getState().simulation.url)
|
||||
const url = getState().simulation?.url
|
||||
url && history.push(url)
|
||||
}
|
||||
|
||||
export function loadPreviousSimulation() {
|
||||
|
@ -155,7 +161,7 @@ export function hideControl(id: string) {
|
|||
return { type: 'HIDE_CONTROL', id } as const
|
||||
}
|
||||
|
||||
export const explainVariable = (variableName = null) =>
|
||||
export const explainVariable = (variableName: DottedName | null = null) =>
|
||||
({
|
||||
type: 'EXPLAIN_VARIABLE',
|
||||
variableName
|
||||
|
|
|
@ -30,7 +30,9 @@ export type Etablissement = {
|
|||
denomination?: string
|
||||
}
|
||||
|
||||
async function searchFullText(text: string): Promise<Array<Etablissement>> {
|
||||
async function searchFullText(
|
||||
text: string
|
||||
): Promise<Array<Etablissement> | null> {
|
||||
const response = await fetch(
|
||||
`https://entreprise.data.gouv.fr/api/sirene/v1/full_text/${text}?per_page=5`
|
||||
)
|
||||
|
|
|
@ -25,11 +25,11 @@ export default function CurrencyInput({
|
|||
const [initialValue, setInitialValue] = useState(valueProp)
|
||||
const [currentValue, setCurrentValue] = useState(valueProp)
|
||||
const onChangeDebounced = useRef(
|
||||
debounceTimeout ? debounce(debounceTimeout, onChange) : onChange
|
||||
debounceTimeout && onChange ? debounce(debounceTimeout, onChange) : onChange
|
||||
)
|
||||
// We need some mutable reference because the <NumberFormat /> component doesn't provide
|
||||
// the DOM `event` in its custom `onValueChange` handler
|
||||
const nextValue = useRef(null)
|
||||
const nextValue = useRef('')
|
||||
|
||||
const inputRef = useRef<HTMLInputElement>()
|
||||
|
||||
|
@ -51,8 +51,8 @@ export default function CurrencyInput({
|
|||
...event.target,
|
||||
value: nextValue.current
|
||||
}
|
||||
nextValue.current = null
|
||||
onChangeDebounced.current(event)
|
||||
nextValue.current = ''
|
||||
onChangeDebounced.current?.(event)
|
||||
}
|
||||
|
||||
const {
|
||||
|
@ -71,7 +71,7 @@ export default function CurrencyInput({
|
|||
<div
|
||||
className={classnames(className, 'currencyInput__container')}
|
||||
{...(valueLength > 5 ? { style: { width } } : {})}
|
||||
onClick={() => inputRef.current.focus()}
|
||||
onClick={() => inputRef.current?.focus()}
|
||||
>
|
||||
{!currentValue && isCurrencyPrefixed && currencySymbol}
|
||||
<NumberFormat
|
||||
|
|
|
@ -6,7 +6,7 @@ import { Trans } from 'react-i18next'
|
|||
type Props = { onEnd: () => void; onCancel: () => void }
|
||||
|
||||
export default function FeedbackForm({ onEnd, onCancel }: Props) {
|
||||
const formRef = useRef<HTMLFormElement>()
|
||||
const formRef = useRef<HTMLFormElement>(null)
|
||||
const tracker = useContext(TrackerContext)
|
||||
|
||||
const handleFormSubmit = (e: React.FormEvent): void => {
|
||||
|
@ -14,7 +14,7 @@ export default function FeedbackForm({ onEnd, onCancel }: Props) {
|
|||
e.preventDefault()
|
||||
fetch('/', {
|
||||
method: 'POST',
|
||||
body: new FormData(formRef.current)
|
||||
body: new FormData(formRef.current ?? undefined)
|
||||
})
|
||||
onEnd()
|
||||
}
|
||||
|
|
|
@ -7,7 +7,9 @@ import { Etablissement, searchDenominationOrSiren } from '../api/sirene'
|
|||
import { debounce } from '../utils'
|
||||
|
||||
export default function Search() {
|
||||
const [searchResults, setSearchResults] = useState<Array<Etablissement>>()
|
||||
const [searchResults, setSearchResults] = useState<Array<
|
||||
Etablissement
|
||||
> | null>()
|
||||
const [isLoading, setLoadingState] = useState(false)
|
||||
|
||||
const handleSearch = useCallback(
|
||||
|
|
|
@ -30,24 +30,26 @@ export default function QuickLinks() {
|
|||
toPairs
|
||||
)(quickLinks)
|
||||
|
||||
if (links.length < 1) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
!!links.length && (
|
||||
<span>
|
||||
<small>Questions :</small>
|
||||
{links.map(([label, dottedName]) => (
|
||||
<button
|
||||
key={dottedName}
|
||||
className={`ui__ link-button ${
|
||||
dottedName === currentQuestion ? 'active' : ''
|
||||
}`}
|
||||
css="margin: 0 0.4rem !important"
|
||||
onClick={() => dispatch(goToQuestion(dottedName))}
|
||||
>
|
||||
<T k={'quicklinks.' + label}>{label}</T>
|
||||
</button>
|
||||
))}{' '}
|
||||
{/* <button className="ui__ link-button">Voir la liste</button> */}
|
||||
</span>
|
||||
)
|
||||
<span>
|
||||
<small>Questions :</small>
|
||||
{links.map(([label, dottedName]) => (
|
||||
<button
|
||||
key={dottedName}
|
||||
className={`ui__ link-button ${
|
||||
dottedName === currentQuestion ? 'active' : ''
|
||||
}`}
|
||||
css="margin: 0 0.4rem !important"
|
||||
onClick={() => dispatch(goToQuestion(dottedName))}
|
||||
>
|
||||
<T k={'quicklinks.' + label}>{label}</T>
|
||||
</button>
|
||||
))}{' '}
|
||||
{/* <button className="ui__ link-button">Voir la liste</button> */}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ export default function SalaryExplanation() {
|
|||
const showDistributionFirst = useSelector(
|
||||
(state: RootState) => !state.conversationSteps.foldedSteps.length
|
||||
)
|
||||
const distributionRef = useRef<HTMLDivElement>()
|
||||
const distributionRef = useRef<HTMLDivElement>(null)
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<Animate.fromTop key={showDistributionFirst.toString()}>
|
||||
|
@ -51,7 +51,7 @@ export default function SalaryExplanation() {
|
|||
<button
|
||||
className="ui__ small simple button"
|
||||
onClick={() =>
|
||||
distributionRef.current.scrollIntoView({
|
||||
distributionRef.current?.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
})
|
||||
|
@ -130,7 +130,7 @@ function PaySlipSection() {
|
|||
return (
|
||||
<section>
|
||||
<h2>
|
||||
{unit.endsWith('mois') ? (
|
||||
{unit?.endsWith('mois') ? (
|
||||
<Trans>Fiche de paie</Trans>
|
||||
) : (
|
||||
<Trans>Détail annuel des cotisations</Trans>
|
||||
|
|
|
@ -17,6 +17,8 @@ type SearchBarProps = {
|
|||
finally?: () => void
|
||||
}
|
||||
|
||||
type Option = Pick<Rule, 'dottedName' | 'name' | 'title'>
|
||||
|
||||
export default function SearchBar({
|
||||
rules,
|
||||
showDefaultList,
|
||||
|
@ -24,7 +26,7 @@ export default function SearchBar({
|
|||
}: SearchBarProps) {
|
||||
const sitePaths = useContext(SitePathsContext)
|
||||
const [input, setInput] = useState('')
|
||||
const [selectedOption, setSelectedOption] = useState(null)
|
||||
const [selectedOption, setSelectedOption] = useState<Option | null>(null)
|
||||
const [results, setResults] = useState([])
|
||||
const { i18n } = useTranslation()
|
||||
|
||||
|
@ -44,7 +46,7 @@ export default function SearchBar({
|
|||
return <ul>{options.map(option => renderOption(option))}</ul>
|
||||
}
|
||||
|
||||
let renderOption = option => {
|
||||
let renderOption = (option: Option) => {
|
||||
let { title, dottedName, name } = option
|
||||
return (
|
||||
<li
|
||||
|
@ -86,14 +88,14 @@ export default function SearchBar({
|
|||
>
|
||||
<Highlighter
|
||||
searchWords={[input]}
|
||||
textToHighlight={title || capitalise0(name)}
|
||||
textToHighlight={title || capitalise0(name) || ''}
|
||||
/>
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
if (selectedOption != null) {
|
||||
if (selectedOption !== null) {
|
||||
finallyCallback && finallyCallback()
|
||||
return (
|
||||
<Redirect
|
||||
|
|
|
@ -87,7 +87,7 @@ export default function StackedBarChart({ data }: StackedBarChartProps) {
|
|||
const [intersectionRef, displayChart] = useDisplayOnIntersecting({
|
||||
threshold: 0.5
|
||||
})
|
||||
const percentages = roundedPercentages(data.map(d => d.nodeValue))
|
||||
const percentages = roundedPercentages(data.map(d => d.nodeValue || 0))
|
||||
const dataWithPercentage = data.map((data, index) => ({
|
||||
...data,
|
||||
percentage: percentages[index]
|
||||
|
|
|
@ -274,7 +274,7 @@ let TargetInputOrValue = ({
|
|||
</>
|
||||
) : (
|
||||
<span>
|
||||
{Number.isNaN(value) ? '—' : formatCurrency(value, language)}
|
||||
{value && Number.isNaN(value) ? '—' : formatCurrency(value, language)}
|
||||
</span>
|
||||
)}
|
||||
{target.dottedName.includes('prix du travail') && <AidesGlimpse />}
|
||||
|
|
|
@ -47,7 +47,7 @@ export default function Value({
|
|||
|
||||
if (
|
||||
(nilValueSymbol !== undefined && nodeValue === 0) ||
|
||||
Number.isNaN(nodeValue) ||
|
||||
(nodeValue && Number.isNaN(nodeValue)) ||
|
||||
nodeValue === null
|
||||
)
|
||||
return (
|
||||
|
@ -63,7 +63,7 @@ export default function Value({
|
|||
(nodeValue as any).nom
|
||||
) : valueType === 'boolean' ? (
|
||||
booleanTranslations[language][nodeValue]
|
||||
) : (
|
||||
) : nodeValue !== undefined ? (
|
||||
formatValue({
|
||||
minimumFractionDigits,
|
||||
maximumFractionDigits,
|
||||
|
@ -71,7 +71,7 @@ export default function Value({
|
|||
unit,
|
||||
value: nodeValue
|
||||
})
|
||||
)
|
||||
) : null
|
||||
return nodeValue == undefined ? null : (
|
||||
<span css={style(customCSS)} className="value">
|
||||
{negative ? '-' : ''}
|
||||
|
|
|
@ -18,9 +18,9 @@ export default function InputSuggestions({
|
|||
onFirstClick,
|
||||
unit
|
||||
}: InputSuggestionsProps) {
|
||||
const [suggestion, setSuggestion] = useState(null)
|
||||
const [suggestion, setSuggestion] = useState<number>()
|
||||
const { t } = useTranslation()
|
||||
const defaultUnit = parseUnit(useSelector(defaultUnitsSelector)[0])
|
||||
const defaultUnit = parseUnit(useSelector(defaultUnitsSelector)[0] ?? '')
|
||||
if (!suggestions) return null
|
||||
|
||||
return (
|
||||
|
|
|
@ -11,7 +11,7 @@ type AnimatedTargetValueProps = {
|
|||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
const formatDifference: typeof formatCurrency = (difference, language) => {
|
||||
const formatDifference = (difference: number, language: string) => {
|
||||
const prefix = difference > 0 ? '+' : ''
|
||||
return prefix + formatCurrency(difference, language)
|
||||
}
|
||||
|
@ -25,12 +25,12 @@ export default function AnimatedTargetValue({
|
|||
|
||||
// We don't want to show the animated if the difference comes from a change in the unit
|
||||
const currentUnit = useSelector(
|
||||
(state: RootState) => state.simulation.defaultUnits[0]
|
||||
(state: RootState) => state?.simulation?.defaultUnits[0]
|
||||
)
|
||||
const previousUnit = useRef(currentUnit)
|
||||
|
||||
const difference =
|
||||
previousValue.current === value || Number.isNaN(value)
|
||||
previousValue.current === value || (value && Number.isNaN(value))
|
||||
? null
|
||||
: (value || 0) - (previousValue.current || 0)
|
||||
const shouldDisplayDifference =
|
||||
|
@ -44,7 +44,7 @@ export default function AnimatedTargetValue({
|
|||
return (
|
||||
<>
|
||||
<span className="Rule-value">
|
||||
{shouldDisplayDifference && (
|
||||
{shouldDisplayDifference && difference !== null && (
|
||||
<Evaporate
|
||||
style={{
|
||||
color: difference > 0 ? 'chartreuse' : 'red',
|
||||
|
|
|
@ -15,7 +15,7 @@ export const getInitialState = (key: string) => {
|
|||
return
|
||||
}
|
||||
try {
|
||||
return JSON.parse(safeLocalStorage.getItem(key))
|
||||
return JSON.parse(value)
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
return null
|
||||
|
|
|
@ -5,7 +5,7 @@ export default function({
|
|||
rootMargin,
|
||||
threshold = 0
|
||||
}: IntersectionObserverInit): [React.RefObject<HTMLDivElement>, boolean] {
|
||||
const ref = useRef<HTMLDivElement>()
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
const [wasOnScreen, setWasOnScreen] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -13,7 +13,7 @@ export default function({
|
|||
([entry]) => {
|
||||
if (entry.isIntersecting) {
|
||||
setWasOnScreen(entry.isIntersecting)
|
||||
observer.unobserve(ref.current)
|
||||
ref.current && observer.unobserve(ref.current)
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -23,11 +23,11 @@ export default function({
|
|||
}
|
||||
)
|
||||
const node = ref.current
|
||||
if (ref.current) {
|
||||
if (node) {
|
||||
observer.observe(node)
|
||||
}
|
||||
return () => {
|
||||
observer.unobserve(node)
|
||||
node && observer.unobserve(node)
|
||||
}
|
||||
}, [root, rootMargin, threshold])
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ export type ThemeColours = ReturnType<typeof generateTheme>
|
|||
export const ThemeColoursContext = createContext<ThemeColours>(generateTheme())
|
||||
|
||||
type ProviderProps = {
|
||||
colour: string
|
||||
colour?: string
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ export let numberFormatter = ({
|
|||
}).format(value)
|
||||
}
|
||||
|
||||
export const currencyFormat = (language: string) => ({
|
||||
export const currencyFormat = (language: string | undefined) => ({
|
||||
isCurrencyPrefixed: !!numberFormatter({ language, style: 'currency' })(
|
||||
12
|
||||
).match(/^€/),
|
||||
|
@ -43,13 +43,13 @@ export const currencyFormat = (language: string) => ({
|
|||
decimalSeparator: numberFormatter({ language })(0.1).charAt(1)
|
||||
})
|
||||
|
||||
export const formatCurrency = (value: number, language: string) => {
|
||||
export const formatCurrency = (value: number | undefined, language: string) => {
|
||||
return value == null
|
||||
? ''
|
||||
: formatValue({ unit: '€', language, value }).replace(/^(-)?€/, '$1€\u00A0')
|
||||
}
|
||||
|
||||
export const formatPercentage = value =>
|
||||
export const formatPercentage = (value: number | undefined) =>
|
||||
value == null
|
||||
? ''
|
||||
: formatValue({ unit: '%', value, maximumFractionDigits: 2 })
|
||||
|
@ -58,7 +58,7 @@ export type formatValueOptions = {
|
|||
maximumFractionDigits?: number
|
||||
minimumFractionDigits?: number
|
||||
language?: string
|
||||
unit: Unit | string
|
||||
unit?: Unit | string
|
||||
value: number
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ export function formatValue({
|
|||
if (typeof value !== 'number') {
|
||||
return value
|
||||
}
|
||||
const serializedUnit = serialiseUnit(unit, value, language)
|
||||
const serializedUnit = unit ? serialiseUnit(unit, value, language) : undefined
|
||||
|
||||
switch (serializedUnit) {
|
||||
case '€':
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
toPairs,
|
||||
values
|
||||
} from 'ramda'
|
||||
import { DottedName } from 'Types/rule'
|
||||
|
||||
/*
|
||||
COLLECTE DES VARIABLES MANQUANTES
|
||||
|
@ -31,7 +32,12 @@ import {
|
|||
missingVariables: {variable: [objectives]}
|
||||
*/
|
||||
|
||||
export let collectMissingVariablesByTarget = (targets = []) =>
|
||||
type Explanation = {
|
||||
missingVariables: Array<DottedName>
|
||||
dottedName: DottedName
|
||||
}
|
||||
|
||||
export let collectMissingVariablesByTarget = (targets: Explanation[] = []) =>
|
||||
fromPairs(targets.map(target => [target.dottedName, target.missingVariables]))
|
||||
|
||||
export let getNextSteps = missingVariablesByTarget => {
|
||||
|
|
|
@ -24,8 +24,9 @@ function MecanismEncadrement({ nodeValue, explanation, unit }) {
|
|||
{!explanation.plancher.isDefault && (
|
||||
<span
|
||||
css={
|
||||
nodeValue === val(explanation.plancher) &&
|
||||
'background: yellow'
|
||||
nodeValue === val(explanation.plancher)
|
||||
? 'background: yellow'
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<strong className="key">Minimum : </strong>
|
||||
|
@ -35,7 +36,9 @@ function MecanismEncadrement({ nodeValue, explanation, unit }) {
|
|||
{!explanation.plafond.isDefault && (
|
||||
<span
|
||||
css={
|
||||
nodeValue === val(explanation.plafond) && 'background: yellow'
|
||||
nodeValue === val(explanation.plafond)
|
||||
? 'background: yellow'
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<strong className="key">Plafonné à : </strong>
|
||||
|
|
|
@ -131,14 +131,16 @@ type CacheMeta = {
|
|||
}
|
||||
}
|
||||
|
||||
export let analyseMany = (parsedRules, targetNames, defaultUnits = []) => (
|
||||
situationGate: (name: DottedName) => any
|
||||
) => {
|
||||
export let analyseMany = (
|
||||
parsedRules,
|
||||
targetNames,
|
||||
defaultUnits: Array<string> = []
|
||||
) => (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)
|
||||
const defaultParsedUnits = defaultUnits.map(parseUnit)
|
||||
let cache = {
|
||||
_meta: { contextRule: [], defaultUnits } as CacheMeta
|
||||
_meta: { contextRule: [], defaultUnits: defaultParsedUnits } as CacheMeta
|
||||
}
|
||||
|
||||
let parsedTargets = targetNames.map(t => {
|
||||
|
|
|
@ -86,7 +86,7 @@ let noUnit = { numerators: [], denominators: [] }
|
|||
export let inferUnit = (
|
||||
operator: SupportedOperators,
|
||||
rawUnits: Array<Unit>
|
||||
): Unit => {
|
||||
): Unit | undefined => {
|
||||
let units = rawUnits.map(u => u || noUnit)
|
||||
if (operator === '*')
|
||||
return simplify({
|
||||
|
@ -109,7 +109,7 @@ export let inferUnit = (
|
|||
return rawUnits.find(u => u)
|
||||
}
|
||||
|
||||
return null
|
||||
return undefined
|
||||
}
|
||||
|
||||
export let removeOnce = <T>(
|
||||
|
|
|
@ -78,10 +78,7 @@ function companyCreationChecklist(
|
|||
}
|
||||
}
|
||||
|
||||
function companyStatusChoice(
|
||||
state: LegalStatus = null,
|
||||
action: Action
|
||||
): LegalStatus {
|
||||
function companyStatusChoice(state: LegalStatus | null = null, action: Action) {
|
||||
if (action.type === 'RESET_COMPANY_STATUS_CHOICE') {
|
||||
return null
|
||||
}
|
||||
|
@ -131,7 +128,7 @@ export type Company = {
|
|||
siren: string
|
||||
catégorieJuridique?: string
|
||||
statutJuridique?: string
|
||||
dateDébutActivité?: Date
|
||||
dateDébutActivité?: string
|
||||
isAutoEntrepreneur?: boolean
|
||||
isDirigeantMajoritaire?: boolean
|
||||
localisation?: GeoDetails & {
|
||||
|
@ -140,7 +137,7 @@ export type Company = {
|
|||
}
|
||||
}
|
||||
|
||||
function existingCompany(state: Company = null, action): Company {
|
||||
function existingCompany(state: Company | null = null, action): Company | null {
|
||||
if (!action.type.startsWith('EXISTING_COMPANY::')) {
|
||||
return state
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Action } from 'Actions/actions'
|
||||
import { Analysis } from 'Engine/traverse'
|
||||
import { areUnitConvertible, convertUnit, parseUnit } from 'Engine/units'
|
||||
import { areUnitConvertible, convertUnit, parseUnit, Unit } from 'Engine/units'
|
||||
import {
|
||||
defaultTo,
|
||||
dissoc,
|
||||
|
@ -22,10 +22,7 @@ import i18n, { AvailableLangs } from '../i18n'
|
|||
import inFranceAppReducer from './inFranceAppReducer'
|
||||
import storageRootReducer from './storageReducer'
|
||||
|
||||
function explainedVariable(
|
||||
state: DottedName = null,
|
||||
action: Action
|
||||
): DottedName {
|
||||
function explainedVariable(state: DottedName | null = null, action: Action) {
|
||||
switch (action.type) {
|
||||
case 'EXPLAIN_VARIABLE':
|
||||
return action.variableName
|
||||
|
@ -36,17 +33,23 @@ function explainedVariable(
|
|||
}
|
||||
}
|
||||
|
||||
function currentExample(state = null, action: Action) {
|
||||
type Example = null | {
|
||||
name: string
|
||||
situation: object
|
||||
dottedName: DottedName
|
||||
defaultUnits?: Array<Unit>
|
||||
}
|
||||
|
||||
function currentExample(state: Example = null, action: Action): Example {
|
||||
switch (action.type) {
|
||||
case 'SET_EXAMPLE':
|
||||
const { situation, name, dottedName } = action
|
||||
return name != null ? { name, situation, dottedName } : null
|
||||
return action.name != null ? action : null
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
function situationBranch(state: number = null, action: Action): number {
|
||||
function situationBranch(state: number | null = null, action: Action) {
|
||||
switch (action.type) {
|
||||
case 'SET_SITUATION_BRANCH':
|
||||
return action.id
|
||||
|
@ -55,10 +58,7 @@ function situationBranch(state: number = null, action: Action): number {
|
|||
}
|
||||
}
|
||||
|
||||
function activeTargetInput(
|
||||
state: DottedName | null = null,
|
||||
action: Action
|
||||
): DottedName | null {
|
||||
function activeTargetInput(state: DottedName | null = null, action: Action) {
|
||||
switch (action.type) {
|
||||
case 'SET_ACTIVE_TARGET_INPUT':
|
||||
return action.name
|
||||
|
@ -83,7 +83,7 @@ function lang(
|
|||
|
||||
type ConversationSteps = {
|
||||
foldedSteps: Array<DottedName>
|
||||
unfoldedStep?: DottedName
|
||||
unfoldedStep?: DottedName | null
|
||||
}
|
||||
|
||||
function conversationSteps(
|
||||
|
@ -178,9 +178,9 @@ export type Simulation = {
|
|||
}
|
||||
|
||||
function simulation(
|
||||
state: Simulation = null,
|
||||
state: Simulation | null = null,
|
||||
action: Action,
|
||||
analysis: Analysis | Array<Analysis>
|
||||
analysis: Analysis | Array<Analysis> | null
|
||||
): Simulation | null {
|
||||
if (action.type === 'SET_SIMULATION') {
|
||||
const { config, url } = action
|
||||
|
@ -272,9 +272,9 @@ const mainReducer = (state, action: Action) =>
|
|||
rules: defaultTo(null) as Reducer<Array<Rule>>,
|
||||
explainedVariable,
|
||||
// We need to access the `rules` in the simulation reducer
|
||||
simulation: (a: Simulation | null, b: Action): Simulation =>
|
||||
simulation: (a: Simulation | null = null, b: Action): Simulation | null =>
|
||||
simulation(a, b, a && analysisWithDefaultsSelector(state)),
|
||||
previousSimulation: defaultTo(null) as Reducer<SavedSimulation>,
|
||||
previousSimulation: defaultTo(null) as Reducer<SavedSimulation | null>,
|
||||
currentExample,
|
||||
situationBranch,
|
||||
activeTargetInput,
|
||||
|
@ -285,6 +285,6 @@ export default reduceReducers<RootState>(
|
|||
existingCompanyRootReducer,
|
||||
mainReducer as any,
|
||||
storageRootReducer as any
|
||||
)
|
||||
) as Reducer<RootState>
|
||||
|
||||
export type RootState = ReturnType<typeof mainReducer>
|
||||
|
|
|
@ -27,7 +27,7 @@ import {
|
|||
zipWith
|
||||
} from 'ramda'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { RootState } from 'Reducers/rootReducer'
|
||||
import { RootState, Simulation } from 'Reducers/rootReducer'
|
||||
import { createSelector, createSelectorCreator, defaultMemoize } from 'reselect'
|
||||
import { DottedName } from 'Types/rule'
|
||||
import { mapOrApply } from '../utils'
|
||||
|
@ -51,7 +51,7 @@ export let ruleDefaultsSelector = createSelector([flatRulesSelector], rules =>
|
|||
export let targetNamesSelector = (state: RootState) => {
|
||||
let objectifs = configSelector(state).objectifs
|
||||
if (!objectifs || !Array.isArray(objectifs)) {
|
||||
return null
|
||||
return []
|
||||
}
|
||||
const targetNames = [].concat(
|
||||
...(objectifs as any).map(objectifOrGroup =>
|
||||
|
@ -121,9 +121,7 @@ const createSituationBrancheSelector = (
|
|||
situation,
|
||||
branches,
|
||||
configSituation
|
||||
):
|
||||
| RootState['simulation']['situation']
|
||||
| Array<RootState['simulation']['situation']> => {
|
||||
): Simulation['situation'] | Array<Simulation['situation']> => {
|
||||
if (branches) {
|
||||
return branches.map(({ situation: branchSituation }) => ({
|
||||
...configSituation,
|
||||
|
@ -215,7 +213,7 @@ export let exampleAnalysisSelector = createSelector(
|
|||
rules,
|
||||
dottedName,
|
||||
(dottedName: DottedName) => situation[dottedName],
|
||||
example.defaultUnits
|
||||
example?.defaultUnits
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
mergeWith,
|
||||
sortBy
|
||||
} from 'ramda'
|
||||
import { RootState } from 'Reducers/rootReducer'
|
||||
import { LegalStatusRequirements, State } from 'Types/companyTypes'
|
||||
|
||||
const LEGAL_STATUS_DETAILS = {
|
||||
|
@ -125,9 +126,7 @@ export const possibleStatusSelector = (state: {
|
|||
}): Record<LegalStatus, boolean> =>
|
||||
possibleStatus(state.inFranceApp.companyLegalStatus)
|
||||
|
||||
export const nextQuestionSelector = (state: {
|
||||
inFranceApp: State
|
||||
}): Question => {
|
||||
export const nextQuestionSelector = (state: RootState): Question | null => {
|
||||
const legalStatusRequirements = state.inFranceApp.companyLegalStatus
|
||||
const questionAnswered = Object.keys(legalStatusRequirements) as Array<
|
||||
Question
|
||||
|
@ -167,7 +166,7 @@ export const nextQuestionSelector = (state: {
|
|||
}
|
||||
|
||||
export const nextQuestionUrlSelector = (
|
||||
state: { inFranceApp: State },
|
||||
state: RootState,
|
||||
{ sitePaths }: { sitePaths: SitePaths }
|
||||
) => {
|
||||
const nextQuestion = nextQuestionSelector(state)
|
||||
|
|
|
@ -98,7 +98,7 @@ export let analysisToCotisations = (analysis: Analysis) => {
|
|||
]
|
||||
.map(name => analysis.cache[name])
|
||||
.map(pathOr([], ['explanation', 'formule', 'explanation', 'explanation']))
|
||||
.reduce(concat, [])
|
||||
.reduce(concat as any, [])
|
||||
|
||||
const cotisations = pipe(
|
||||
map((rule: any) =>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { RootState } from 'Reducers/rootReducer'
|
||||
import { RootState, Simulation } from 'Reducers/rootReducer'
|
||||
|
||||
// Note: it is currently not possible to define SavedSimulation as the return
|
||||
// type of the currentSimulationSelector function because the type would then
|
||||
// circulary reference itself.
|
||||
export type SavedSimulation = {
|
||||
situation: RootState['simulation']['situation']
|
||||
situation: Simulation['situation']
|
||||
activeTargetInput: RootState['activeTargetInput']
|
||||
foldedSteps: RootState['conversationSteps']['foldedSteps']
|
||||
}
|
||||
|
@ -13,21 +13,25 @@ export const currentSimulationSelector = (
|
|||
state: RootState
|
||||
): SavedSimulation => {
|
||||
return {
|
||||
situation: state.simulation.situation,
|
||||
situation: state.simulation?.situation ?? {},
|
||||
activeTargetInput: state.activeTargetInput,
|
||||
foldedSteps: state.conversationSteps.foldedSteps
|
||||
}
|
||||
}
|
||||
|
||||
export const createStateFromSavedSimulation = (state: RootState) =>
|
||||
state.previousSimulation && {
|
||||
activeTargetInput: state.previousSimulation.activeTargetInput,
|
||||
simulation: {
|
||||
...state.simulation,
|
||||
situation: state.previousSimulation.situation || {}
|
||||
},
|
||||
conversationSteps: {
|
||||
foldedSteps: state.previousSimulation.foldedSteps
|
||||
},
|
||||
previousSimulation: null
|
||||
}
|
||||
export const createStateFromSavedSimulation = (
|
||||
state: RootState
|
||||
): Partial<RootState> =>
|
||||
state.previousSimulation
|
||||
? {
|
||||
activeTargetInput: state.previousSimulation.activeTargetInput,
|
||||
simulation: {
|
||||
...state.simulation,
|
||||
situation: state.previousSimulation.situation || {}
|
||||
} as Simulation,
|
||||
conversationSteps: {
|
||||
foldedSteps: state.previousSimulation.foldedSteps
|
||||
},
|
||||
previousSimulation: null
|
||||
}
|
||||
: {}
|
||||
|
|
|
@ -15,7 +15,7 @@ export default function AfterRegistration() {
|
|||
(state: RootState) => state.inFranceApp.companyStatusChoice
|
||||
)
|
||||
const { t } = useTranslation()
|
||||
const isAutoentrepreneur = statutChoisi.match('auto-entrepreneur')
|
||||
const isAutoentrepreneur = statutChoisi?.match('auto-entrepreneur')
|
||||
|
||||
return (
|
||||
<Animate.fromBottom>
|
||||
|
|
|
@ -38,20 +38,21 @@ export default function PreviousAnswers() {
|
|||
const legalStatus = useSelector(
|
||||
(state: RootState) => state.inFranceApp.companyLegalStatus
|
||||
)
|
||||
if (Object.values(legalStatus).length < 1) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
!!Object.values(legalStatus).length && (
|
||||
<ul css="margin-bottom: -1rem;">
|
||||
{Object.entries(legalStatus).map(
|
||||
([key, value]) =>
|
||||
!isNil(value) && (
|
||||
<li key={key}>
|
||||
<Link to={sitePaths.créer.guideStatut[key]}>
|
||||
{requirementToText(key as any, value as any)}
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
)}
|
||||
</ul>
|
||||
)
|
||||
<ul css="margin-bottom: -1rem;">
|
||||
{Object.entries(legalStatus).map(
|
||||
([key, value]) =>
|
||||
!isNil(value) && (
|
||||
<li key={key}>
|
||||
<Link to={sitePaths.créer.guideStatut[key]}>
|
||||
{requirementToText(key as any, value as any)}
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
)}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -21,8 +21,10 @@ export default function IntegrationTest() {
|
|||
script.src = window.location.origin + '/simulateur-iframe-integration.js'
|
||||
script.dataset.module = currentModule
|
||||
script.dataset.couleur = colour
|
||||
domNode.current.innerHTML = ''
|
||||
domNode.current.appendChild(script)
|
||||
if (domNode.current) {
|
||||
domNode.current.innerHTML = ''
|
||||
domNode.current.appendChild(script)
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [version])
|
||||
return (
|
||||
|
|
|
@ -11,6 +11,7 @@ const aideMidiPyrenéesAutoEntrepreneur = (state: RootState) => {
|
|||
return false
|
||||
}
|
||||
return (
|
||||
company.dateDébutActivité &&
|
||||
new Date(company.dateDébutActivité) > new Date('2019-04-01') &&
|
||||
company.isAutoEntrepreneur &&
|
||||
company.localisation &&
|
||||
|
|
|
@ -20,7 +20,7 @@ import * as Animate from 'Ui/animate'
|
|||
import AideOrganismeLocal from './AideOrganismeLocal'
|
||||
import businessPlan from './businessPlan.svg'
|
||||
|
||||
const infereRégimeFromCompanyDetails = (company: Company) => {
|
||||
const infereRégimeFromCompanyDetails = (company: Company | null) => {
|
||||
if (!company) {
|
||||
return null
|
||||
}
|
||||
|
@ -28,14 +28,14 @@ const infereRégimeFromCompanyDetails = (company: Company) => {
|
|||
return 'auto-entrepreneur'
|
||||
}
|
||||
if (
|
||||
['EI', 'EURL'].includes(company.statutJuridique) ||
|
||||
['EI', 'EURL'].includes(company.statutJuridique ?? '') ||
|
||||
(company.statutJuridique === 'SARL' && company.isDirigeantMajoritaire)
|
||||
) {
|
||||
return 'indépendant'
|
||||
}
|
||||
|
||||
if (
|
||||
['SASU', 'SAS'].includes(company.statutJuridique) ||
|
||||
['SASU', 'SAS'].includes(company.statutJuridique ?? '') ||
|
||||
(company.statutJuridique === 'SARL' && !company.isDirigeantMajoritaire)
|
||||
) {
|
||||
return 'assimilé-salarié'
|
||||
|
@ -193,7 +193,7 @@ export default function SocialSecurity() {
|
|||
}
|
||||
|
||||
type CompanySectionProps = {
|
||||
company: Company
|
||||
company: Company | null
|
||||
}
|
||||
|
||||
const CompanySection = ({ company }: CompanySectionProps) => {
|
||||
|
@ -203,7 +203,7 @@ const CompanySection = ({ company }: CompanySectionProps) => {
|
|||
false
|
||||
)
|
||||
|
||||
const companyRef = useRef(null)
|
||||
const companyRef = useRef<Company | null>(null)
|
||||
useEffect(() => {
|
||||
if (companyRef.current !== company) {
|
||||
companyRef.current = company
|
||||
|
|
|
@ -147,12 +147,13 @@ function WarningRegimeSpecial() {
|
|||
const situation = useSelector(situationSelector)
|
||||
const recettes = situation['artiste-auteur . revenus . BNC . recettes']
|
||||
const showWarning = recettes !== 0 && recettes >= 70000
|
||||
if (!showWarning) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
showWarning && (
|
||||
<li>
|
||||
Vos revenus ne vous permettent pas d'opter pour le régime micro-BNC.
|
||||
</li>
|
||||
)
|
||||
<li>
|
||||
Vos revenus ne vous permettent pas d'opter pour le régime micro-BNC.
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -179,23 +180,25 @@ function CotisationsResult() {
|
|||
setDisplay(true)
|
||||
}
|
||||
|
||||
if (!display) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
display && (
|
||||
<Animate.appear>
|
||||
<ResultBlock className="ui__ card">
|
||||
<ResultLabel>Montant des cotisations</ResultLabel>
|
||||
<RuleLink dottedName={cotisationRule.dottedName}>
|
||||
{formatValue({
|
||||
value: cotisationRule.nodeValue,
|
||||
language: 'fr',
|
||||
unit: '€',
|
||||
maximumFractionDigits: 0
|
||||
})}
|
||||
</RuleLink>
|
||||
</ResultBlock>
|
||||
{cotisationRule.nodeValue ? <RepartitionCotisations /> : null}
|
||||
</Animate.appear>
|
||||
)
|
||||
<Animate.appear>
|
||||
<ResultBlock className="ui__ card">
|
||||
<ResultLabel>Montant des cotisations</ResultLabel>
|
||||
<RuleLink dottedName={cotisationRule.dottedName}>
|
||||
{formatValue({
|
||||
value: cotisationRule.nodeValue,
|
||||
language: 'fr',
|
||||
unit: '€',
|
||||
maximumFractionDigits: 0
|
||||
})}
|
||||
</RuleLink>
|
||||
</ResultBlock>
|
||||
{cotisationRule.nodeValue ? <RepartitionCotisations /> : null}
|
||||
</Animate.appear>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
export let capitalise0 = (name: string): string =>
|
||||
export let capitalise0 = (name: string | undefined) =>
|
||||
name && name[0].toUpperCase() + name.slice(1)
|
||||
|
||||
export function debounce<ArgType>(
|
||||
timeout: number,
|
||||
fn: (arg?: ArgType) => void
|
||||
): (arg?: ArgType) => void {
|
||||
export const debounce = <F extends (...args: any[]) => void>(
|
||||
waitFor: number,
|
||||
fn: F
|
||||
) => {
|
||||
let timeoutId: ReturnType<typeof setTimeout>
|
||||
return (...args) => {
|
||||
return (...args: any[]) => {
|
||||
clearTimeout(timeoutId)
|
||||
timeoutId = setTimeout(() => fn(...args), timeout)
|
||||
timeoutId = setTimeout(() => fn(...args), waitFor)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,9 +16,13 @@
|
|||
// strictBindCallApply, strictNullChecks, strictFunctionTypes, and
|
||||
// strictPropertyInitialization. During the transition we enable these
|
||||
// settings one by one.
|
||||
// Note: almost all parameters are now enabled. The only one remaining
|
||||
// is noImplicitAny -- but it's a hard one.
|
||||
"noImplicitThis": true,
|
||||
"strictBindCallApply": true,
|
||||
"strictFunctionTypes": true,
|
||||
"strictNullChecks": true,
|
||||
"strictPropertyInitialization": true,
|
||||
"paths": {
|
||||
"Actions/*": ["actions/*"],
|
||||
"Components": ["components"],
|
||||
|
|
Loading…
Reference in New Issue