diff --git a/source/Provider.tsx b/source/Provider.tsx index bfb0ef02c..ec36264a7 100644 --- a/source/Provider.tsx +++ b/source/Provider.tsx @@ -96,7 +96,7 @@ export default function Provider({ onStoreCreated?.(store) // Remove loader - const css = document.createElement('style') + var css = document.createElement('style') css.type = 'text/css' css.innerHTML = ` #js { diff --git a/source/components/MoreInfosOnUs.tsx b/source/components/MoreInfosOnUs.tsx new file mode 100644 index 000000000..8ff719af2 --- /dev/null +++ b/source/components/MoreInfosOnUs.tsx @@ -0,0 +1,86 @@ +import React, { useContext } from 'react' +import emoji from 'react-easy-emoji' +import { useTranslation } from 'react-i18next' +import { Link, useLocation } from 'react-router-dom' +import { icons } from './ui/SocialIcon' +import { SitePathsContext } from './utils/withSitePaths' + +export default function MoreInfosOnUs() { + const { pathname } = useLocation() + const sitePaths = useContext(SitePathsContext) + const { language } = useTranslation().i18n + + if (language !== 'fr') { + return null + } + + return ( +
+

+ Plus d'infos sur mon-entreprise.fr +

+ {!pathname.startsWith(sitePaths.nouveautés) && ( + +
{emoji('✨')}
+

Les nouveautés

+

+ Qu'avons-nous mis en production ces derniers mois ? +

+
Découvrir
+ + )} + +
{emoji('📊')}
+

Les statistiques

+

+ Quel est notre impact ? +

+
Découvrir
+
+ {!pathname.startsWith(sitePaths.budget) && ( + +
{emoji('💶')}
+

Le budget

+

+ Quelles sont nos ressources et comment sont-elles employées ? +

+
Découvrir
+ + )} + +
+ {' '} + + + + + +
+

Le code source

+

+ Nos travaux sont ouverts et libres de droit, ça se passe sur GitHub +

+
Découvrir
+
+
+ ) +} diff --git a/source/components/ui/index.css b/source/components/ui/index.css index 54810e000..99ff5340c 100644 --- a/source/components/ui/index.css +++ b/source/components/ui/index.css @@ -137,3 +137,18 @@ span.ui__.enumeration:not(:last-of-type)::after { .no-scroll { overflow: hidden; } + +.markdown table { + text-align: left; + margin-bottom: 1rem; + width: 100%; +} + +.markdown table tbody tr:nth-child(2n + 1) { + background-color: var(--lighterColor); +} + +.markdown table td, +.markdown table th { + padding: 5px 10px; +} diff --git a/source/locales/en.yaml b/source/locales/en.yaml index d26cb8326..2b9334452 100644 --- a/source/locales/en.yaml +++ b/source/locales/en.yaml @@ -61,7 +61,7 @@ Gérant minoritaire: Managing director Habituellement: Usually Imprimer: Print Impôts: Taxes -"Indemnité chômage partiel prise en charge par l'état :": 'State-paid short-time working allowance :' +'Indemnité chômage partiel prise en charge par l''état :': 'State-paid short-time working allowance :' Indépendant: Independent International: International Intégrer l'interface de simulation: Integrate the simulation interface @@ -78,7 +78,7 @@ Mon entreprise: My company Mon revenu: My income Montant: Amount 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' @@ -143,7 +143,7 @@ Taux: Rate Taux calculé: Calculated rate Taux moyen: Average rate Total des retenues: Total withheld -"Total payé par l'entreprise :": 'Total paid by the company :' +'Total payé par l''entreprise :': 'Total paid by the company :' Tout effacer: Delete all Tranche de l'assiette: Scale bracket Un seul associé: Only one partner @@ -891,6 +891,7 @@ pages: module: What module? par: per path: + budget: /budget coronavirus: /coronavirus créer: après: /after-registration diff --git a/source/sites/mon-entreprise.fr/App.tsx b/source/sites/mon-entreprise.fr/App.tsx index 33c54aff7..c3195c7f7 100644 --- a/source/sites/mon-entreprise.fr/App.tsx +++ b/source/sites/mon-entreprise.fr/App.tsx @@ -23,6 +23,7 @@ import './App.css' import Footer from './layout/Footer/Footer' import Header from './layout/Header' import trackSimulatorActions from './middlewares/trackSimulatorActions' +import Budget from './pages/Budget/Budget' import Coronavirus from './pages/Coronavirus' import Créer from './pages/Créer' import IntegrationTest from './pages/Dev/IntegrationTest' @@ -127,6 +128,7 @@ const App = () => { + { <> {' • '} Nouveautés + {' • '} + Stats + {' • '} + Budget )} {' • '} - Stats - {' • '} Intégrer nos simulateurs diff --git a/source/sites/mon-entreprise.fr/pages/Budget/Budget.tsx b/source/sites/mon-entreprise.fr/pages/Budget/Budget.tsx new file mode 100644 index 000000000..ff5c54667 --- /dev/null +++ b/source/sites/mon-entreprise.fr/pages/Budget/Budget.tsx @@ -0,0 +1,126 @@ +import MoreInfosOnUs from 'Components/MoreInfosOnUs' +import { Markdown } from 'Components/utils/markdown' +import { ScrollToTop } from 'Components/utils/Scroll' +import { formatCurrency } from 'Engine/format' +import { sum, uniq } from 'ramda' +import React, { useState } from 'react' +import emoji from 'react-easy-emoji' +import { useTranslation } from 'react-i18next' +import styled from 'styled-components' +import prose from './budget.md' +import budget from './budget.yaml' + +// Splitting the markdown file to insert React components in-between is a bit +// arcane, we may consider MDX in the future https://github.com/mdx-js/mdx. +const [ + intro, + ressources2019, + ressources2020, + ressourcesDescription +] = prose.split(/\r?\n-{3,}\r?\n/) + +const ressources = { + 2019: ressources2019, + 2020: ressources2020 +} + +export default function Budget() { + const [selectedYear, setSelectedYear] = useState('2020') + const years = ['2019', '2020'] + const quarters = ['T1', 'T2', 'T3', 'T4'] + const categories = uniq( + quarters + .map(q => Object.keys(budget[2020][q] ?? {})) + .reduce((acc, curr) => [...acc, ...curr], []) + ) + + const { language } = useTranslation().i18n + return ( + <> + +

Budget {emoji('💶')}

+ + + + {selectedYear !== '2019' && ( + <> +

Emploi des ressources

+ + + + 2020 + {quarters.map(q => ( + {q} + ))} + + + + {categories.map(label => ( + + {label} + {quarters.map(q => { + const value = budget[2020]?.[q]?.[label] + return ( + + {value ? formatCurrency(value, language) : '-'} + + ) + })} + + ))} + + + + Total + + {formatCurrency( + sum(Object.values(budget[2020]['T1'])), + language + )} + + - + - + - + + + + + + )} + + + ) +} + +const RessourcesAllocationTable = styled.table` + width: 100%; + text-align: left; + td { + padding: 6px; + } + + td:not(:first-child) { + width: 100px; + text-align: right; + } + + tbody tr:nth-child(2n + 1), + tfoot tr { + background: var(--lighterColor); + } + + thead, + tfoot { + font-weight: bold; + } +` diff --git a/source/sites/mon-entreprise.fr/pages/Budget/budget.md b/source/sites/mon-entreprise.fr/pages/Budget/budget.md new file mode 100644 index 000000000..706881869 --- /dev/null +++ b/source/sites/mon-entreprise.fr/pages/Budget/budget.md @@ -0,0 +1,102 @@ +**Mon-Entreprise.fr** est une start-up d'État financée par de l'argent public, +c'est pourquoi nous sommes transparents sur les ressources allouées et la +manière dont elles sont employées. + +## Principes + +Notre organisation souscrit aux principes établis dans le [manifeste des startup +d'État](https://beta.gouv.fr/incubateurs) que nous rappelons ici : + +> ### Considère les besoins des usagers avant ceux de l’administration + +> Il cible ses investissements sur des sujets qui en valent la peine, +> c’est-à-dire où existe un réel irritant supporté par des milliers ou des +> millions de personnes. Il ne soutient pas d’investissement qui n’ait obtenu de +> plébiscite usagers au-delà de 6 mois, il incite donc à la confrontation la +> plus rapide au terrain. + +> ### Pilote ses équipes par la finalité plus que par les moyens + +> Son mode de gestion repose sur la confiance. Une autonomie maximale est +> concédée aux équipes, pilotées uniquement par leurs objectifs d’impact et non +> par leurs moyens. Il veille en particulier à ne leur imposer aucune des +> contraintes inhérentes à la structure (comitologie, communication, achat, +> standard technologique…). + +> ### S’améliore en continu plus qu’il n’obéit à un plan + +> Il s’impose à lui-même la méthode frugale et incrémentale qu’il promeut. En +> particulier, son objectif initial est de lancer le plus rapidement possible +> une première startup puis d’améliorer en continu ses méthodes, ses produits et +> les compétences de ses membres. Dans son portefeuille, rien n’est en +> maintenance, tout est soit en vie, soit stoppé. + +--- + +## Budget + +En 2019, le projet dispose d'un budget de **250 000 € HT** pris en charge : + +- Par la DINSIC (ancien nom de la [DINUM](https://www.numerique.gouv.fr/dinum/)) à hauteur de 150 000 € HT +- Par l'[ACOSS](https://www.acoss.fr) à hauteur de 100 000 € HT + +[➡ Voir la convention](https://static.data.gouv.fr/resources/conventions-de-partenariat/20190423-181035/convention-du-15-avril-2019.pdf) + +| | | +| -------------------------- | ---------------- | +| Financement DINSIC | 150 000 € HT | +| Financement Acoss initial | 100 000 € HT | +| Rallonge Acoss fin d'année | 12 500 € HT | +| **Total** | **262 500 € HT** | + +En fin d'année une rallonge de a été attribuée pour la réalisation d'un nouveau +simulateur et une expérimentation sur la paie. + +--- + +## Budget provisionnel + +En 2020, le budget de **250 000 € HT** est reconduit. Il est pris en charge +à 100% par l’[ACOSS](https://www.acoss.fr). + +De plus, une enveloppe de **41 667 € HT** est allouée pour expérimenter la +transformation de notre moteur de simulations en moteur de paie complète. + +| | | +| --------------------------- | ---------------- | +| Budget mon-entreprise | 250 000 € HT | +| Budget expérimentation paie | 41 667 € HT | +| **Total** | **291 667 € HT** | + +En plus de cette contribution financière, l'ACOSS fournit des ressources métier +expertes provenant du réseau des URSSAF. + +--- + +### Description des catégories + +- **Développement 👨‍💻** + + Les coûts de développement répresentent la grande majorité de notre budget. + Nous utilisons une petite équipe de développeurs freelances, qui sont + pluridisciplinaires aussi bien sur les aspects techniques, stratégiques et + métiers. + +- **Logiciels et hébergement 💻** + + Notre modèle open-source nous permet d'accéder gratuitement à la majorité des + outils que nous utilisions (hébergement de code, serveurs de tests, etc.). Le + site est hebergé sur [Netlify](https://www.netlify.com). + +- **Déplacements 🚅** + + Le réseau des URSSAF est présent dans toutes la France. Nous organisions + plusieurs fois par an des ateliers avec des experts en région sur des + thématiques particulières. Sont aussi inclus dans cette catégories la prise en + charge des frais de déplacements des développeurs qui ne sont pas situés en + région parisienne. + +- **Documentation 📖** + + Nous achetons de la documentation spécialisée à destination des professionnels + du droit afin de faciliter l'implémentation des dipositifs législatifs. diff --git a/source/sites/mon-entreprise.fr/pages/Budget/budget.yaml b/source/sites/mon-entreprise.fr/pages/Budget/budget.yaml new file mode 100644 index 000000000..1d84bd837 --- /dev/null +++ b/source/sites/mon-entreprise.fr/pages/Budget/budget.yaml @@ -0,0 +1,11 @@ +# Ces données sont optenues avec la commande suivante depuis le repo privé +# `compa-mon-entreprise` : +# +# $ hledger bal charges -p 2020 -Q -B --depth 2 + +2020: + T1: + Développement: 73500 + Logiciels et hébergement: 170 + Déplacements: 742 + Documentation: 286 diff --git a/source/sites/mon-entreprise.fr/pages/Nouveautés/Nouveautés.tsx b/source/sites/mon-entreprise.fr/pages/Nouveautés/Nouveautés.tsx index 3a28ffd2d..fb751255b 100644 --- a/source/sites/mon-entreprise.fr/pages/Nouveautés/Nouveautés.tsx +++ b/source/sites/mon-entreprise.fr/pages/Nouveautés/Nouveautés.tsx @@ -1,3 +1,4 @@ +import MoreInfosOnUs from 'Components/MoreInfosOnUs' import { Markdown } from 'Components/utils/markdown' import { ScrollToTop } from 'Components/utils/Scroll' import { SitePathsContext } from 'Components/utils/withSitePaths' @@ -50,20 +51,17 @@ export default function Nouveautés() { les{' '} {selectedRelease === 0 ? 'dernières nouveautés' - : `nouveautés de ${data[selectedRelease].name.toLowerCase()}`}{' '} - : + : `nouveautés de ${data[selectedRelease].name.toLowerCase()}`} +  :

{ history.push(getPath(Number(evt.target.value))) }} > {data.map(({ name }, index) => ( - ))} @@ -100,6 +98,7 @@ export default function Nouveautés() { + ) } diff --git a/source/sites/mon-entreprise.fr/sitePaths.ts b/source/sites/mon-entreprise.fr/sitePaths.ts index b7575e101..04129e035 100644 --- a/source/sites/mon-entreprise.fr/sitePaths.ts +++ b/source/sites/mon-entreprise.fr/sitePaths.ts @@ -126,6 +126,7 @@ export const constructLocalizedSitePath = (language: string) => { ) }, nouveautés: t('path.nouveautés', '/nouveautés'), + budget: t('path.budget', '/budget'), documentation: { index: t('path.documentation.index', '/documentation'), rule: (dottedName: DottedName) => '/' + encodeRuleName(dottedName) diff --git a/source/types/import-markdown.ts b/source/types/import-markdown.ts new file mode 100644 index 000000000..a20f1eb04 --- /dev/null +++ b/source/types/import-markdown.ts @@ -0,0 +1,4 @@ +declare module '*.md' { + const content: string + export default content +}