diff --git a/source/components/utils/SetCssColor.js b/source/components/utils/SetCssColor.js deleted file mode 100644 index 7c5405e64..000000000 --- a/source/components/utils/SetCssColor.js +++ /dev/null @@ -1,21 +0,0 @@ -import { Component } from 'react' - -class SetCSSColor extends Component { - updateCSSColor = () => { - Object.entries(this.props.colors).forEach(([key, value]) => { - document.body.style.setProperty(`--${key}`, value) - }, this.props.colors) - } - constructor(props) { - super(props) - this.updateCSSColor() - } - componentDidUpdate() { - this.updateCSSColor() - } - render() { - return null - } -} - -export default SetCSSColor diff --git a/source/components/utils/colors.tsx b/source/components/utils/colors.tsx index 7124b0682..fbd46b3a6 100644 --- a/source/components/utils/colors.tsx +++ b/source/components/utils/colors.tsx @@ -1,6 +1,5 @@ import convert from 'color-convert' -import SetCssColor from 'Components/utils/SetCssColor' -import React, { createContext } from 'react' +import React, { createContext, useEffect, useRef } from 'react' /* Hex to RGB conversion: @@ -101,10 +100,17 @@ type ProviderProps = { export function ThemeColorsProvider({ color, children }: ProviderProps) { const colors = generateTheme(color) + const divRef = useRef(null) + useEffect(() => { + Object.entries(colors).forEach(([key, value]) => { + if (typeof value === 'string') { + divRef.current?.style.setProperty(`--${key}`, value) + } + }, colors) + }, [colors]) return ( - - {children} +
{children}
) } diff --git a/source/locales/en.yaml b/source/locales/en.yaml index 3307e0b29..71442afed 100644 --- a/source/locales/en.yaml +++ b/source/locales/en.yaml @@ -17,6 +17,7 @@ Changer: Change Chercher dans la documentation: Search the documentation Choisir la forme juridique: Choose your legal status Choisir plus tard: Choose later +Code d'intégration: Integration Code Commencer: Get started 'Commerçant, artisan, ou libéral ?': 'Trader, craftsman, or liberal?' Continuer: Continue @@ -62,7 +63,7 @@ Modifier mes réponses: Change my answers Mon entreprise: My company Mon revenu: My income Montant des cotisations: Amount of contributions -"Nom de l'entreprise ou SIREN ": Company name or SIREN code +'Nom de l''entreprise ou SIREN ': Company name or SIREN code Non: 'No' Nous n'avons rien trouvé: We didn't find any matching registered company. Oui: 'Yes' @@ -74,12 +75,16 @@ Part salarié: Employee share Pas en auto-entrepreneur: Not in auto-entrepreneur Pas implémenté: Not implemented Passer: Skip +Personnalisez l'integration: Customize the integration Plein écran: Fullscreen Plus d'informations: More information (fr) Plusieurs associés: Several partners Prochaines questions: Next questions Protection sociale: Social security Précédent: Previous +Prévisualisation: Preview +Quel module ?: What module? +Quelle couleur ?: What color? Quelques exemples de salaires: Some salary exemples Quelques intégrations: Some integrations Recherche en cours...: Searching... @@ -115,6 +120,7 @@ Total des retenues: Total withheld Tout effacer: Delete all Tranche de l'assiette: Scale bracket Un seul associé: Only one partner +Une idée ?<1>Contactez-nous !: Any ideas?<1>Contact us! Vie privée: Privacy Voir la répartition des cotisations: View contribution breakdown Voir le code source: See the source code @@ -780,10 +786,14 @@ pages: bibliothèque: "<0>Integrate our calculation library<1>If you think that your site or service would benefit from displaying salary calculations, for example switching from gross salary to net salary, good news: all the contribution and tax calculations behind my-company.fr are free and <2>can be integrated in the form of an <2>NPM library.<2>Put simply, your team's developers are able to integrate the calculation into your interface in 5 minutes{emoji('⌚')}, without having to deal with the complexity of payroll and the regular updating of calculation rules.<3>This library is a common digital library developed by the State and ACOSS. It is based on a new programming language, <2>publicodes.<4>How to use it?<5>The following examples show you how to use the library on a very simple ReactJs site.<6>1) Make a very simple calculation: from gross to net<7><0><8>2) Browse online documentation<9>As you can see from the previous example, the recipe for a calculation is simple: input variables (gross wage), one or more output variables (net wage).<10>All these variables are listed and explained in our <2>online documentation.<11>Use the search engine to find the right variable, then click on \"View source code\" to get all the documentation: default value, possible values when it's an enumeration of choice, unit when it's a number, description, associated user question, etc.<12>Let's run a calculation closer to a payslip: Here is a description of the input situation with links to the corresponding pages of the documentation :<13> An <3>executive earning <7>€3,400 gross, who benefits from the<10> bicycle mileage allowance and works in a company with <14>12 employees.<14>The calculation for this more complete example is as follows:<15><0><16>{emoji('ℹ️ ')} Note that in the previous example we have to specify the transport payment rate ourselves.<17>Whereas in the <2>employee simulator, it is sufficient to fill in the municipality and the corresponding rate is automatically determined. It's intentional: to keep the library (and the site) light, we use two online APIs. The<4> Geo API - communes to switch from the commune name to the common code. Then the<7> transport payout API, developed and maintained by us, which is not documented but its use is very simple and understandable <10>in this React component that calls it, a component that also uses the common API.<18>Making economic charts{emoji(' \U0001F4C8')}<19>It is also possible to use the library for economic or political analysis calculations. Here, the price of labour and the net wage is plotted against the gross wage.<20>We can see the progressiveness of the total wage, which is in percent lower for a minimum wage than for a high income. In other words, high-wage earners pay part of the social security contributions of low-wage earners.<21>{emoji('⚠️ ')}Beware, this example does a lot of calculations in one go, which can block your browser for a few seconds. To overcome this problem, you would have to call the library in a Web Worker, but this is not possible for the <3>moment in these demos.<22><0>" développeurs: choice: + github: >- + <0>Contribute to GitHub<1>All our tools are open and publicly + developed on GitHub. library: >- <0>Using the calculation engine<1>The entire socio-fiscal calculation engine developed by URSSAF, freely available in the form of an NPM library. + code à copier: 'Here is the code to copy and paste on your site:' home: choice: iframe: >- @@ -799,13 +809,12 @@ pages: users. titre: Integrate social security law at the heart of your tools iframe: >- - <0>Integrate the Web module<1>By adding a line to your web page - :<2><3>You can <2>choose the main color of the module to blend - it into the visual theme of your page: just change the <4>data-color - value above. To choose it, use our <7>interactive tool.<4>The + <0>Integrate the Web module<1>Our simulators can be seamlessly + integrated by adding a simple line of code to your web page.<2>You can + choose the simulator to integrate and <2>customize the main color of the + module to blend it into the visual theme of your page.<3>The attribute <1>data-lang="en" allows you to choose English as the - default language of the simulator (it will remain modifiable by the - user). + simulator language. par: per path: créer: diff --git a/source/sites/mon-entreprise.fr/App.tsx b/source/sites/mon-entreprise.fr/App.tsx index ca4aa62bb..2f4a52358 100644 --- a/source/sites/mon-entreprise.fr/App.tsx +++ b/source/sites/mon-entreprise.fr/App.tsx @@ -25,7 +25,6 @@ import Footer from './layout/Footer/Footer' import Header from './layout/Header' import trackSimulatorActions from './middlewares/trackSimulatorActions' import Créer from './pages/Créer' -import Couleur from './pages/Dev/Couleur' import IntegrationTest from './pages/Dev/IntegrationTest' import Personas from './pages/Dev/Personas' import Sitemap from './pages/Dev/Sitemap' @@ -128,7 +127,6 @@ const App = () => { path="/dev/integration-test" component={IntegrationTest} /> - diff --git a/source/sites/mon-entreprise.fr/pages/Dev/ColorPicker.tsx b/source/sites/mon-entreprise.fr/pages/Dev/ColorPicker.tsx index 76ca10ebf..447354cd5 100644 --- a/source/sites/mon-entreprise.fr/pages/Dev/ColorPicker.tsx +++ b/source/sites/mon-entreprise.fr/pages/Dev/ColorPicker.tsx @@ -3,11 +3,9 @@ import { ChromePicker } from 'react-color' export default function ColorPicker({ color, onChange }) { return ( -
- onChange(color.hex)} - /> -
+ onChange(color.hex)} + /> ) } diff --git a/source/sites/mon-entreprise.fr/pages/Dev/Couleur.tsx b/source/sites/mon-entreprise.fr/pages/Dev/Couleur.tsx deleted file mode 100644 index 0b4166d18..000000000 --- a/source/sites/mon-entreprise.fr/pages/Dev/Couleur.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { - ThemeColorsContext, - ThemeColorsProvider -} from 'Components/utils/colors' -import React, { Suspense, useContext, useState } from 'react' -import Home from '../Iframes/SimulateurEmbauche' -let LazyColorPicker = React.lazy(() => import('./ColorPicker')) - -export default function Couleur() { - const { color: defaultColor } = useContext(ThemeColorsContext) - const [color, setColor] = useState(defaultColor) - return ( - <> -

Changez la couleur de l'integration

-

- Visualisez sur cette page l’apparence du module pour différentes - couleurs principales. -

- Chargement...}> - - -

- La couleur sélectionnée, à déclarer comme attribut - "data-couleur" du script sur votre page est : {color} -

-
- - - -
- - ) -} diff --git a/source/sites/mon-entreprise.fr/pages/Dev/IntegrationTest.tsx b/source/sites/mon-entreprise.fr/pages/Dev/IntegrationTest.tsx index 4664668a6..b52717ed4 100644 --- a/source/sites/mon-entreprise.fr/pages/Dev/IntegrationTest.tsx +++ b/source/sites/mon-entreprise.fr/pages/Dev/IntegrationTest.tsx @@ -1,7 +1,7 @@ import React, { Suspense } from 'react' let LazyColorPicker = React.lazy(() => import('./ColorPicker')) -const integrableModuleNames = [ +export const integrableModuleNames = [ 'simulateur-embauche', 'simulateur-autoentrepreneur', 'simulateur-independant', @@ -56,70 +56,13 @@ export default function IntegrationTest() {
0 ? 'block' : 'none'}; `} > -

Code d'intégration

- -
-
-
+
) } - -export let IntegrationCode = ({ - module = 'simulateur-embauche', - color = '#2975D1' -}) => ( - - {'<'} - - script -
- id -
- ="script-simulateur-embauche" - data-module=" - {module}"data-couleur=" - {color}" src - ="https://mon-entreprise.fr/simulateur-iframe-integration.js"> - {'<'} - / - script - > -
-) diff --git a/source/sites/mon-entreprise.fr/pages/Iframes/index.tsx b/source/sites/mon-entreprise.fr/pages/Iframes/index.tsx index a1bd26fa2..145790604 100644 --- a/source/sites/mon-entreprise.fr/pages/Iframes/index.tsx +++ b/source/sites/mon-entreprise.fr/pages/Iframes/index.tsx @@ -1,6 +1,7 @@ import { IsEmbeddedContext } from 'Components/utils/embeddedContext' import React from 'react' import { Route } from 'react-router' +import { inIframe } from '../../../../utils' import SimulateurArtisteAuteur from '../Simulateurs/ArtisteAuteur' import SimulateurAssimiléSalarié from '../Simulateurs/AssimiléSalarié' import SimulateurAutoEntrepreneur from '../Simulateurs/AutoEntrepreneur' @@ -36,7 +37,7 @@ export default function Iframes() { path="/iframes/simulateur-artiste-auteur" component={SimulateurArtisteAuteur} /> - + {inIframe() && }
) diff --git a/source/sites/mon-entreprise.fr/pages/Simulateurs/ArtisteAuteur.tsx b/source/sites/mon-entreprise.fr/pages/Simulateurs/ArtisteAuteur.tsx index 4d256d4d2..639bd760a 100644 --- a/source/sites/mon-entreprise.fr/pages/Simulateurs/ArtisteAuteur.tsx +++ b/source/sites/mon-entreprise.fr/pages/Simulateurs/ArtisteAuteur.tsx @@ -4,6 +4,7 @@ import RuleLink from 'Components/RuleLink' import SimulateurWarning from 'Components/SimulateurWarning' import config from 'Components/simulationConfigs/artiste-auteur.yaml' import 'Components/TargetSelection.css' +import { IsEmbeddedContext } from 'Components/utils/embeddedContext' import { formatValue } from 'Engine/format' import InputComponent from 'Engine/RuleInput' import { getRuleFromAnalysis } from 'Engine/rules' @@ -41,14 +42,17 @@ export default function ArtisteAuteur() { const dispatch = useDispatch() dispatch(setSimulationConfig(config)) const initialRender = useInitialRender() + const inIframe = useContext(IsEmbeddedContext) return ( <> -

- - Estimer mes cotisations d’artiste-auteur - -

+ {!inIframe && ( +

+ + Estimer mes cotisations d’artiste-auteur + +

+ )}
diff --git a/source/sites/mon-entreprise.fr/pages/Simulateurs/AssimiléSalarié.tsx b/source/sites/mon-entreprise.fr/pages/Simulateurs/AssimiléSalarié.tsx index 5651e97ac..9d2283a07 100644 --- a/source/sites/mon-entreprise.fr/pages/Simulateurs/AssimiléSalarié.tsx +++ b/source/sites/mon-entreprise.fr/pages/Simulateurs/AssimiléSalarié.tsx @@ -3,7 +3,8 @@ import SalaryExplanation from 'Components/SalaryExplanation' import Warning from 'Components/SimulateurWarning' import Simulation from 'Components/Simulation' import assimiléConfig from 'Components/simulationConfigs/assimilé.yaml' -import React from 'react' +import { IsEmbeddedContext } from 'Components/utils/embeddedContext' +import React, { useContext } from 'react' import { Helmet } from 'react-helmet' import { Trans, useTranslation } from 'react-i18next' import { useDispatch } from 'react-redux' @@ -13,8 +14,8 @@ export default function AssimiléSalarié() { const dispatch = useDispatch() const location = useLocation() dispatch(setSimulationConfig(assimiléConfig, location.state?.fromGérer)) - const { t } = useTranslation() + const inIframe = useContext(IsEmbeddedContext) return ( <> @@ -33,11 +34,13 @@ export default function AssimiléSalarié() { )} /> -

- - Simulateur de revenus assimilé salarié - -

+ {!inIframe && ( +

+ + Simulateur de revenus assimilé salarié + +

+ )} } /> diff --git a/source/sites/mon-entreprise.fr/pages/Simulateurs/AutoEntrepreneur.tsx b/source/sites/mon-entreprise.fr/pages/Simulateurs/AutoEntrepreneur.tsx index f8fb934a8..022ce2712 100644 --- a/source/sites/mon-entreprise.fr/pages/Simulateurs/AutoEntrepreneur.tsx +++ b/source/sites/mon-entreprise.fr/pages/Simulateurs/AutoEntrepreneur.tsx @@ -4,6 +4,7 @@ import Simulation from 'Components/Simulation' import autoEntrepreneurConfig from 'Components/simulationConfigs/auto-entrepreneur.yaml' import StackedBarChart from 'Components/StackedBarChart' import { ThemeColorsContext } from 'Components/utils/colors' +import { IsEmbeddedContext } from 'Components/utils/embeddedContext' import { getRuleFromAnalysis } from 'Engine/rules' import { default as React, useContext } from 'react' import { Helmet } from 'react-helmet' @@ -15,6 +16,7 @@ import { analysisWithDefaultsSelector } from 'Selectors/analyseSelectors' export default function AutoEntrepreneur() { const dispatch = useDispatch() const location = useLocation() + const inIframe = useContext(IsEmbeddedContext) dispatch( setSimulationConfig(autoEntrepreneurConfig, location.state?.fromGérer) ) @@ -38,11 +40,13 @@ export default function AutoEntrepreneur() { )} /> -

- - Simulateur de revenus auto-entrepreneur - -

+ {!inIframe && ( +

+ + Simulateur de revenus auto-entrepreneur + +

+ )} } /> diff --git a/source/sites/mon-entreprise.fr/pages/Simulateurs/Indépendant.tsx b/source/sites/mon-entreprise.fr/pages/Simulateurs/Indépendant.tsx index 3ed7827ea..404ab8e17 100644 --- a/source/sites/mon-entreprise.fr/pages/Simulateurs/Indépendant.tsx +++ b/source/sites/mon-entreprise.fr/pages/Simulateurs/Indépendant.tsx @@ -4,6 +4,7 @@ import Simulation from 'Components/Simulation' import indépendantConfig from 'Components/simulationConfigs/indépendant.yaml' import StackedBarChart from 'Components/StackedBarChart' import { ThemeColorsContext } from 'Components/utils/colors' +import { IsEmbeddedContext } from 'Components/utils/embeddedContext' import { getRuleFromAnalysis } from 'Engine/rules' import { default as React, useContext } from 'react' import { Helmet } from 'react-helmet' @@ -17,6 +18,8 @@ export default function Indépendant() { const location = useLocation() dispatch(setSimulationConfig(indépendantConfig, location.state?.fromGérer)) const { t } = useTranslation() + const inIframe = useContext(IsEmbeddedContext) + return ( <> @@ -34,11 +37,13 @@ export default function Indépendant() { )} /> -

- - Simulateur de revenus pour indépendants - -

+ {!inIframe && ( +

+ + Simulateur de revenus pour indépendants + +

+ )} } /> diff --git a/source/sites/mon-entreprise.fr/pages/integration/Iframe.tsx b/source/sites/mon-entreprise.fr/pages/integration/Iframe.tsx index bf8b56d61..f37c12aab 100644 --- a/source/sites/mon-entreprise.fr/pages/integration/Iframe.tsx +++ b/source/sites/mon-entreprise.fr/pages/integration/Iframe.tsx @@ -1,15 +1,118 @@ +import { ThemeColorsProvider } from 'Components/utils/colors' import { ScrollToTop } from 'Components/utils/Scroll' import urssafLogo from 'Images/urssaf.svg' -import React from 'react' +import React, { Suspense, useRef, useState } from 'react' import { Trans } from 'react-i18next' -import { Link } from 'react-router-dom' -import { IntegrationCode } from '../Dev/IntegrationTest' +import { MemoryRouter } from 'react-router-dom' +import { integrableModuleNames } from '../Dev/IntegrationTest' +import Iframes from '../Iframes' import './iframe.css' import apecLogo from './images/apec.png' import cciLogo from './images/cci.png' import minTraLogo from './images/min-tra.jpg' import poleEmploiLogo from './images/pole-emploi.png' +let LazyColorPicker = React.lazy(() => import('../Dev/ColorPicker')) + +function IntegrationCustomizer() { + const [currentModule, setCurrentModule] = React.useState( + integrableModuleNames[0] + ) + const [color, setColor] = useState() + return ( +
+

+ Personnalisez l'integration +

+
+
+
+

+ Quel module ? +

+ + +

+ Quelle couleur ? +

+ Chargement...
}> + + +

+ Code d'intégration +

+

+ + Voici le code à copier-coller sur votre site : + +

+ +
+
+

+ Prévisualisation +

+ + + + + +
+
+
+
+ ) +} + export default function Integration() { return ( <> @@ -17,26 +120,26 @@ export default function Integration() {

Intégrez le module Web

-

En ajoutant une ligne à votre page Web :

-

- Vous pouvez choisir la couleur principale du module{' '} - pour le fondre dans le thème visuel de votre page : changez - simplement la valeur de data-couleur ci-dessus. Pour la - choisir, utilisez notre{' '} - outil interactif. + Nous simulateurs sont intégrables de manière transparante en + ajoutant une simple ligne de code à votre page Web. +

+

+ Vous pouvez choisir le simulateur à intégrer et{' '} + personnaliser la couleur principale du module pour + le fondre dans le thème visuel de votre page.

L'attribut data-lang="en" vous permet quand à lui de choisir - l'anglais comme langue par défaut du simulateur (elle restera - modifiable par l'utilisateur). + l'anglais comme langue du simulateur.

- + ) } + +type IntegrationCodeProps = { + module?: string + color?: string +} + +function IntegrationCode({ + module = 'simulateur-embauche', + color +}: IntegrationCodeProps) { + const codeRef = useRef(null) + const [secondClick, setSecondClick] = useState(false) + const selectAllCode = () => { + if (codeRef.current && !secondClick) { + const range = document.createRange() + range.selectNode(codeRef.current) + window.getSelection()?.removeAllRanges() + window.getSelection()?.addRange(range) + setSecondClick(true) + } + if (secondClick) { + setSecondClick(false) + } + } + return ( + + {'<'} + + script +
+ id +
+ ="script-simulateur-embauche" +
+ data-module=" + {module}" + {color ? ( + <> +
+ data-couleur=" + {color}" + + ) : ( + '' + )} +
+ src + ="https://mon-entreprise.fr/simulateur-iframe-integration.js"> + {'<'} + / + script + > +
+ ) +}