wip
parent
a3f73a551c
commit
22e6288658
|
@ -1,4 +1,3 @@
|
|||
import { ThemeColorsContext } from 'Components/utils/colors'
|
||||
import useDisplayOnIntersecting from 'Components/utils/useDisplayOnIntersecting'
|
||||
import { formatValue } from 'publicodes'
|
||||
import React, { useContext } from 'react'
|
||||
|
@ -7,18 +6,32 @@ import { useTranslation } from 'react-i18next'
|
|||
import { animated, config, useSpring } from 'react-spring'
|
||||
import { DisableAnimationContext } from './utils/DisableAnimationContext'
|
||||
|
||||
const ANIMATION_SPRING = config.gentle
|
||||
|
||||
type ChartItemBarProps = {
|
||||
numberToPlot: number
|
||||
unit?: string
|
||||
style: React.CSSProperties
|
||||
display: boolean
|
||||
percentage: number
|
||||
}
|
||||
|
||||
function ChartItemBar({ style, numberToPlot, unit }: ChartItemBarProps) {
|
||||
function ChartItemBar({
|
||||
numberToPlot,
|
||||
unit,
|
||||
display,
|
||||
percentage,
|
||||
}: ChartItemBarProps) {
|
||||
const language = useTranslation().i18n.language
|
||||
const style = useSpring({
|
||||
config: config.slow,
|
||||
delay: 100,
|
||||
immediate: useContext(DisableAnimationContext),
|
||||
from: {
|
||||
flex: 0,
|
||||
},
|
||||
flex: display ? percentage : 0,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="distribution-chart__bar-container">
|
||||
<div className="distribution-chart__bar-container ui__ print-background-force">
|
||||
<animated.div className="distribution-chart__bar" style={style} />
|
||||
<div
|
||||
css={`
|
||||
|
@ -65,23 +78,20 @@ export default function BarChartBranch({
|
|||
const [intersectionRef, brancheInViewport] = useDisplayOnIntersecting({
|
||||
threshold: 0.5,
|
||||
})
|
||||
const numberToPlot = brancheInViewport ? value : 0
|
||||
const styles = useSpring({
|
||||
config: ANIMATION_SPRING,
|
||||
to: {
|
||||
flex: numberToPlot / maximum,
|
||||
opacity: numberToPlot ? 1 : 0,
|
||||
const disableAnimation = useContext(DisableAnimationContext)
|
||||
const display = disableAnimation || brancheInViewport
|
||||
const style = useSpring({
|
||||
from: {
|
||||
opacity: 0,
|
||||
},
|
||||
}) as { flex: number; opacity: number } // TODO: problème avec les types de react-spring ?
|
||||
|
||||
return !useContext(DisableAnimationContext) ? (
|
||||
<animated.div
|
||||
ref={intersectionRef}
|
||||
className="distribution-chart__item"
|
||||
style={{ opacity: styles.opacity }}
|
||||
>
|
||||
immediate: disableAnimation,
|
||||
opacity: display ? 1 : 0,
|
||||
})
|
||||
return (
|
||||
<animated.div ref={intersectionRef} style={style}>
|
||||
<InnerBarChartBranch
|
||||
value={numberToPlot}
|
||||
value={value}
|
||||
display={display}
|
||||
maximum={maximum}
|
||||
title={title}
|
||||
unit={unit}
|
||||
|
@ -89,15 +99,6 @@ export default function BarChartBranch({
|
|||
description={description}
|
||||
/>
|
||||
</animated.div>
|
||||
) : (
|
||||
<InnerBarChartBranch
|
||||
value={value}
|
||||
maximum={maximum}
|
||||
title={title}
|
||||
unit={unit}
|
||||
icon={icon}
|
||||
description={description}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -106,6 +107,7 @@ type InnerBarChartBranchProps = {
|
|||
icon?: string
|
||||
maximum: number
|
||||
description?: string
|
||||
display: boolean
|
||||
unit?: string
|
||||
value: number
|
||||
}
|
||||
|
@ -115,12 +117,12 @@ function InnerBarChartBranch({
|
|||
title,
|
||||
icon,
|
||||
maximum,
|
||||
display,
|
||||
description,
|
||||
unit,
|
||||
}: InnerBarChartBranchProps) {
|
||||
const { color } = useContext(ThemeColorsContext)
|
||||
return (
|
||||
<>
|
||||
<div className="distribution-chart__item">
|
||||
{icon && <BranchIcon icon={icon} />}
|
||||
<div className="distribution-chart__item-content">
|
||||
<p className="distribution-chart__counterparts">
|
||||
|
@ -129,14 +131,12 @@ function InnerBarChartBranch({
|
|||
{description && <small>{description}</small>}
|
||||
</p>
|
||||
<ChartItemBar
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
flex: value / maximum,
|
||||
}}
|
||||
display={display}
|
||||
numberToPlot={value}
|
||||
percentage={value / maximum}
|
||||
unit={unit}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
.distribution-chart__bar {
|
||||
border-radius: 0.4em;
|
||||
background-color: var(--color);
|
||||
|
||||
min-height: 1.5em;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
.payslip__container h4 {
|
||||
border-bottom: 1px solid black;
|
||||
color-adjust: exact !important;
|
||||
margin: 0;
|
||||
margin-top: 1.5em;
|
||||
padding-bottom: 0.5em;
|
||||
|
|
|
@ -6,6 +6,7 @@ import { ASTNode, formatValue, ParsedRules, reduceAST } from 'publicodes'
|
|||
import { RuleNode } from 'publicodes/dist/types/rule'
|
||||
import { Fragment, useContext } from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { ExplicableRule } from './conversation/Explicable'
|
||||
import './PaySlip.css'
|
||||
import { Line, SalaireBrutSection, SalaireNetSection } from './PaySlipSections'
|
||||
|
||||
|
@ -124,7 +125,10 @@ export default function PaySlip() {
|
|||
return (
|
||||
<Fragment key={section.dottedName}>
|
||||
<h5 className="payslip__cotisationTitle">
|
||||
<RuleLink dottedName={section.dottedName} />
|
||||
{section.title}{' '}
|
||||
<em className="ui__ print-display-none">
|
||||
<ExplicableRule dottedName={section.dottedName} />
|
||||
</em>
|
||||
</h5>
|
||||
{cotisations.map((cotisation) => (
|
||||
<Cotisation key={cotisation} dottedName={cotisation} />
|
||||
|
@ -216,14 +220,14 @@ function Cotisation({ dottedName }: { dottedName: DottedName }) {
|
|||
<>
|
||||
<RuleLink
|
||||
dottedName={dottedName}
|
||||
style={{ backgroundColor: 'var(--lightestColor)' }}
|
||||
className="ui__ lighter-bg print-background-force"
|
||||
/>
|
||||
<span style={{ backgroundColor: 'var(--lightestColor)' }}>
|
||||
<span className="ui__ lighter-bg print-background-force">
|
||||
{partPatronale?.nodeValue
|
||||
? formatValue(partPatronale, { displayedUnit: '€', language })
|
||||
: '–'}
|
||||
</span>
|
||||
<span style={{ backgroundColor: 'var(--lightestColor)' }}>
|
||||
<span className="ui__ lighter-bg print-background-force">
|
||||
{partSalariale?.nodeValue
|
||||
? formatValue(partSalariale, { displayedUnit: '€', language })
|
||||
: '–'}
|
||||
|
|
|
@ -242,7 +242,7 @@ function TargetInputOrValue({
|
|||
)}
|
||||
</span>
|
||||
{(isActive || isFocused) && (
|
||||
<div style={{ minWidth: '100%' }}>
|
||||
<div style={{ minWidth: '100%' }} className="ui__ print-display-none">
|
||||
<FromTop>
|
||||
<div css="display: flex; justify-content: flex-end; margin-bottom: -0.4rem">
|
||||
<InputSuggestions
|
||||
|
|
|
@ -4,14 +4,14 @@ import { Trans } from 'react-i18next'
|
|||
|
||||
export default function ExportRecover() {
|
||||
return (
|
||||
<section className="screen-display-none print-break-avoid">
|
||||
<h2>
|
||||
<Trans i18nKey="pages.simulateurs.print-info.title">
|
||||
Vous souhaitez retrouver cette simulation ?
|
||||
</Trans>
|
||||
</h2>
|
||||
|
||||
<section className="ui__ screen-display-none print-break-avoid notice">
|
||||
<p>
|
||||
<strong>
|
||||
<Trans i18nKey="pages.simulateurs.print-info.title">
|
||||
Vous souhaitez retrouver cette simulation ?
|
||||
</Trans>
|
||||
</strong>
|
||||
|
||||
<Trans i18nKey="pages.simulateurs.print-info.recover">
|
||||
Retrouvez la, ainsi que d'autres outils d'aide à la création et à la
|
||||
gestion d'entreprise, sur{' '}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Value, { Condition } from 'Components/EngineValue'
|
||||
import { FromBottom } from 'Components/ui/animate'
|
||||
import Emoji from 'Components/utils/Emoji'
|
||||
import { useEngine } from 'Components/utils/EngineContext'
|
||||
import assuranceMaladieSrc from 'Images/assurance-maladie.svg'
|
||||
|
|
|
@ -3,7 +3,6 @@ import PaySlip from 'Components/PaySlip'
|
|||
import StackedBarChart from 'Components/StackedBarChart'
|
||||
import { FromTop } from 'Components/ui/animate'
|
||||
import { ThemeColorsContext } from 'Components/utils/colors'
|
||||
import Emoji from 'Components/utils/Emoji'
|
||||
import { useInversionFail } from 'Components/utils/EngineContext'
|
||||
import { useContext, useRef } from 'react'
|
||||
import emoji from 'react-easy-emoji'
|
||||
|
@ -108,7 +107,7 @@ function RevenueRepartitionSection(props: { onSeePayslip: () => void }) {
|
|||
|
||||
function PaySlipSection() {
|
||||
return (
|
||||
<section className="ui__ print-break-avoid">
|
||||
<section>
|
||||
<h2>
|
||||
<Trans>Fiche de paie</Trans>
|
||||
</h2>
|
||||
|
@ -129,11 +128,12 @@ export const DistributionSection = ({
|
|||
{children}
|
||||
<p className="ui__ notice">
|
||||
<Trans>
|
||||
<Emoji emoji="ℹ" /> Pour en savoir plus, rendez-vous sur le site{' '}
|
||||
Pour en savoir plus, rendez-vous sur le site{' '}
|
||||
<a href="https://www.aquoiserventlescotisations.urssaf.fr/">
|
||||
aquoiserventlescotisations.urssaf.fr
|
||||
</a>
|
||||
</Trans>
|
||||
</p>
|
||||
<div className="ui__ print-break-after" />
|
||||
</section>
|
||||
)
|
||||
|
|
|
@ -7,6 +7,13 @@ html {
|
|||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
html {
|
||||
line-height: 1.4rem;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
@media (min-width: 500px) and (max-width: 1920px) {
|
||||
html {
|
||||
font-size: 1.1em;
|
||||
|
@ -18,12 +25,6 @@ html {
|
|||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
html {
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
font-weight: 400;
|
||||
color: #040e19;
|
||||
|
|
|
@ -209,7 +209,7 @@ input.ui__::placeholder {
|
|||
color: grey;
|
||||
}
|
||||
@media screen {
|
||||
.screen-display-none {
|
||||
.ui__.screen-display-none {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
@ -220,14 +220,15 @@ input.ui__::placeholder {
|
|||
}
|
||||
|
||||
.ui__.print-break-avoid {
|
||||
page-break-inside: avoid;
|
||||
break-inside: avoid;
|
||||
}
|
||||
|
||||
.ui__.print-break-after {
|
||||
break-after: always;
|
||||
}
|
||||
|
||||
.ui__.print-background-force {
|
||||
color-adjust: exact !important;
|
||||
-webkit-print-color-adjust: exact !important;
|
||||
print-color-adjust: exact !important;
|
||||
}
|
||||
|
||||
.ui__.toggle input[type='radio']:checked ~ * {
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import React, { createContext, useCallback, useEffect, useState } from 'react'
|
||||
export const DisableAnimationContext = createContext(false)
|
||||
|
||||
export function DisableAnimationOnPrintProvider({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
export const useIsPrintContext = () => {
|
||||
const [isPrintContext, setPrintContext] = useState(false)
|
||||
const onPrintContextChange = useCallback(
|
||||
(matchMedia: MediaQueryListEvent | MediaQueryList) => {
|
||||
|
@ -22,6 +18,24 @@ export function DisableAnimationOnPrintProvider({
|
|||
}
|
||||
}, [onPrintContextChange])
|
||||
|
||||
// Fix for Firefox (see https://bugzilla.mozilla.org/show_bug.cgi?id=774398)
|
||||
useEffect(() => {
|
||||
window.onbeforeprint = () => setPrintContext(true)
|
||||
return () => {
|
||||
window.onbeforeprint = null
|
||||
}
|
||||
}, [setPrintContext])
|
||||
|
||||
return isPrintContext
|
||||
}
|
||||
|
||||
export function DisableAnimationOnPrintProvider({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
const isPrintContext = useIsPrintContext()
|
||||
console.log(isPrintContext)
|
||||
return (
|
||||
<DisableAnimationContext.Provider value={isPrintContext}>
|
||||
{children}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useIsPrintContext } from './DisableAnimationContext'
|
||||
|
||||
export default function ({
|
||||
root = null,
|
||||
|
@ -41,7 +42,8 @@ export default function ({
|
|||
return () => {
|
||||
node && unobserve && observer.unobserve(node)
|
||||
}
|
||||
}, [root, rootMargin, threshold, ref.current])
|
||||
}, [root, rootMargin, threshold, unobserve])
|
||||
|
||||
return [ref, wasOnScreen]
|
||||
const isPrintContext = useIsPrintContext()
|
||||
return [ref, isPrintContext || wasOnScreen]
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { Condition } from 'Components/EngineValue'
|
||||
import PreviousSimulationBanner from 'Components/PreviousSimulationBanner'
|
||||
import ExportRecover from 'Components/simulationExplanation/ExportRecover'
|
||||
import { ThemeColorsProvider } from 'Components/utils/colors'
|
||||
import { IsEmbeddedContext } from 'Components/utils/embeddedContext'
|
||||
import Emoji from 'Components/utils/Emoji'
|
||||
|
@ -87,10 +86,10 @@ export default function PageData({
|
|||
<ThemeColorsProvider color={inIframe ? undefined : meta?.color}>
|
||||
<Component />
|
||||
{config && <PreviousSimulationBanner />}
|
||||
<div className="ui__ print-break-after" />
|
||||
{!inIframe && (
|
||||
<>
|
||||
{seoExplanations}
|
||||
<ExportRecover></ExportRecover>
|
||||
<NextSteps
|
||||
iframePath={privateIframe ? undefined : iframePath}
|
||||
nextSteps={nextSteps}
|
||||
|
|
|
@ -139,7 +139,7 @@ export function getSimulatorsData({
|
|||
shortName: t('pages.simulateurs.salarié.shortname', 'Salarié'),
|
||||
seoExplanations: (
|
||||
<Trans i18nKey="pages.simulateurs.salarié.seo">
|
||||
<section className="ui__ print-break-avoid">
|
||||
<section>
|
||||
<h2>Comment calculer le salaire net ?</h2>
|
||||
<p>
|
||||
Lors de l'entretien d'embauche l'employeur propose en général une
|
||||
|
@ -256,7 +256,7 @@ export function getSimulatorsData({
|
|||
),
|
||||
seoExplanations: (
|
||||
<Trans i18nKey="pages.simulateurs.ei.seo explanation">
|
||||
<section className="ui__ print-break-avoid">
|
||||
<section>
|
||||
<h2>
|
||||
Comment calculer le revenu net d'un dirigeant d'entreprise
|
||||
individuelle (EI) ?
|
||||
|
@ -398,7 +398,7 @@ export function getSimulatorsData({
|
|||
},
|
||||
seoExplanations: (
|
||||
<Trans i18nKey="pages.simulateurs.sasu.seo-explanation">
|
||||
<section className="ui__ print-break-avoid">
|
||||
<section>
|
||||
<h2>Comment calculer le salaire d'un dirigeant de SASU ? </h2>
|
||||
<p>
|
||||
Comme pour un salarié classique, le{' '}
|
||||
|
@ -516,7 +516,7 @@ export function getSimulatorsData({
|
|||
),
|
||||
seoExplanations: (
|
||||
<Trans i18nKey="pages.simulateurs.auto-entrepreneur.seo explanation">
|
||||
<section className="ui__ print-break-avoid">
|
||||
<section>
|
||||
<h2>Comment calculer le revenu net d'un auto-entrepreneur ?</h2>
|
||||
<p>
|
||||
Un auto-entrepreneur doit payer des cotisations et contributions
|
||||
|
@ -673,7 +673,7 @@ export function getSimulatorsData({
|
|||
),
|
||||
seoExplanations: (
|
||||
<Trans i18nKey="pages.simulateurs.chômage-partiel.seo">
|
||||
<section className="ui__ print-break-avoid">
|
||||
<section>
|
||||
<h2>Comment calculer l'indemnité d'activité partielle ?</h2>
|
||||
<p>
|
||||
L'indemnité d'activité partielle de base est fixée par la loi à{' '}
|
||||
|
@ -1077,7 +1077,7 @@ export function getSimulatorsData({
|
|||
component: ISSimulation,
|
||||
seoExplanations: (
|
||||
<Trans i18nKey="pages.simulateurs.is.seo">
|
||||
<section className="ui__ print-break-avoid">
|
||||
<section>
|
||||
<h2>Comment est calculé l’impôt sur les sociétés ?</h2>
|
||||
<p>
|
||||
L’impôt sur les sociétés s’applique aux bénéfices réalisés par les
|
||||
|
|
Loading…
Reference in New Issue