diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c64693cb4..ed4b70404 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,7 +25,6 @@ Nous utilisons : - [Prettier](https://prettier.io/) pour formater le code source, l'idéal est de configurer votre éditeur de texte pour que les fichiers soit formatés automatiquement quand vous sauvegardez un fichier. Si vous utilisez [VS Code](https://code.visualstudio.com/) cette configuration est automatique. - [ViteJS](https://vitejs.dev) pour le “bundling” et le serveur de développement - [Eslint](http://eslint.org) qui permet par exemple d'éviter de garder des variables inutilisées -- [Ramda](https://ramdajs.com) comme libraire d'utilitaires pour manipuler les listes/objects/etc (c'est une alternative à lodash ou underscore) - [Vitest](https://vitest.dev) et [Cypress](https://www.cypress.io) pour les l'execution des tests. Plus d'informations dans la section consacrée aux tests. ### Démarrage diff --git a/site/scripts/fetch-stats.js b/site/scripts/fetch-stats.js index 4ab27028b..30ead5419 100644 --- a/site/scripts/fetch-stats.js +++ b/site/scripts/fetch-stats.js @@ -2,8 +2,6 @@ import 'dotenv/config.js' import 'isomorphic-fetch' import fs from 'fs' import path from 'path' -import { filter, flatten, map, partition, pipe } from 'ramda' -import { compose } from 'redux' import { fileURLToPath } from 'url' import { createDataDir, writeInDataDir } from './utils.js' @@ -157,21 +155,23 @@ const last36Months = { .slice(0, 8) + '01', end: yesterday, } -const uniformiseData = pipe( - // For some reason, an artifact create ghost page with unlogical chapter metrics... - // It seems to only by one per month thought... This hacks resolves it - filter(({ m_visits }) => m_visits === undefined || m_visits > 2), - map(({ d_evo_day, d_evo_month, m_visits, m_events, ...data }) => ({ - date: d_evo_day != null ? d_evo_day : d_evo_month, - nombre: m_visits != null ? m_visits : m_events, - ...data, - })) -) -const flattenPage = compose( - flatten, - map(({ Rows, ...page }) => Rows.map((r) => ({ ...page, ...r }))), - filter((p) => p.page_chapter2 !== 'N/A') // Remove simulateur landing page -) +const uniformiseData = (data) => + data + .map(({ d_evo_day, d_evo_month, m_visits, m_events, ...data }) => ({ + date: d_evo_day != null ? d_evo_day : d_evo_month, + nombre: m_visits != null ? m_visits : m_events, + ...data, + })) + // For some reason, an artifact create ghost page with unlogical chapter metrics... + // It seems to only by one per month thought... This hacks resolves it + .filter(({ m_visits }) => m_visits === undefined || m_visits > 2) + +const flattenPage = (list) => + list + .flat() + .map(({ Rows, ...page }) => Rows.map((r) => ({ ...page, ...r }))) + .filter((p) => p.page_chapter2 !== 'N/A') // Remove simulateur landing page + async function fetchDailyVisits() { const pages = uniformiseData( flattenPage(await fetchApi(buildSimulateursQuery(last60days, 'D'))) @@ -261,12 +261,12 @@ async function fetchUserFeedbackIssues() { const issues = Object.entries(data.data.repository) .filter(([, value]) => !!value) .map(([k, value]) => ({ ...value, count: +/[\d]+$/.exec(k)[0] })) - const [closed, open] = partition((s) => s.closedAt, issues) + return { - open, - closed: closed.sort( - (i1, i2) => new Date(i2.closedAt) - new Date(i1.closedAt) - ), + open: issues.filter((s) => !s.closedAt), + closed: issues + .filter((s) => s.closedAt) + .sort((i1, i2) => new Date(i2.closedAt) - new Date(i1.closedAt)), } } async function main() { diff --git a/site/scripts/i18n/utils.js b/site/scripts/i18n/utils.js index bd7fb66d9..7a18901cc 100644 --- a/site/scripts/i18n/utils.js +++ b/site/scripts/i18n/utils.js @@ -2,7 +2,7 @@ import 'dotenv/config.js' import { readFileSync } from 'fs' import 'isomorphic-fetch' import { stringify } from 'querystring' -import { equals, mergeAll, path as _path, pick, toPairs } from 'ramda' +import { equals, mergeAll, path as _path, pick } from 'ramda' import yaml from 'yaml' import rules from '../../../modele-social/dist/index.js' @@ -36,7 +36,7 @@ export function getRulesMissingTranslations() { ]) .map(([dottedName, rule]) => ({ [dottedName]: mergeAll( - toPairs(rule) + Object.entries(rule) .filter(([, v]) => !!v) .map(([k, v]) => { let attrToTranslate = attributesToTranslate.find(equals(k)) diff --git a/site/source/components/Distribution.tsx b/site/source/components/Distribution.tsx index 1accbbb1c..d9ce2f85c 100644 --- a/site/source/components/Distribution.tsx +++ b/site/source/components/Distribution.tsx @@ -1,6 +1,5 @@ import { EngineContext, useEngine } from '@/components/utils/EngineContext' import { DottedName } from 'modele-social' -import { max } from 'ramda' import { useContext } from 'react' import { useSelector } from 'react-redux' import { targetUnitSelector } from '@/selectors/simulationSelectors' @@ -28,7 +27,7 @@ export default function Distribution() { .filter(([, value]) => value > 0) .sort(([, a], [, b]) => b - a) - const maximum = distribution.map(([, value]) => value).reduce(max, 0) + const maximum = Math.max(...distribution.map(([, value]) => value)) return (
diff --git a/site/source/components/conversation/InputSuggestions.tsx b/site/source/components/conversation/InputSuggestions.tsx index 389170a01..1f6d47a27 100644 --- a/site/source/components/conversation/InputSuggestions.tsx +++ b/site/source/components/conversation/InputSuggestions.tsx @@ -1,7 +1,6 @@ import { Link } from '@/design-system/typography/link' import { SmallBody } from '@/design-system/typography/paragraphs' import { ASTNode } from 'publicodes' -import { toPairs } from 'ramda' import { useState } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' @@ -27,7 +26,7 @@ export default function InputSuggestions({ return ( - {toPairs(suggestions).map(([text, value]: [string, ASTNode]) => { + {Object.entries(suggestions).map(([text, value]: [string, ASTNode]) => { return ( - {hrefLink.map(({ href, hrefLang }) => ( + {hrefLink && ( - ))} + )}
)} - {hrefLink.map(({ hrefLang, href }) => ( -
  • - - {hrefLang === 'fr' ? ( + {hrefLink && ( +
  • + + {hrefLink.hrefLang === 'fr' ? ( <> Passer en français - ) : hrefLang === 'en' ? ( + ) : hrefLink.hrefLang === 'en' ? ( <> Switch to English ) : ( - hrefLang + hrefLink.hrefLang )}
  • - ))} + )} diff --git a/site/source/components/simulationExplanation/IndépendantExplanation.tsx b/site/source/components/simulationExplanation/IndépendantExplanation.tsx index 9263b0710..e14b1b189 100644 --- a/site/source/components/simulationExplanation/IndépendantExplanation.tsx +++ b/site/source/components/simulationExplanation/IndépendantExplanation.tsx @@ -14,7 +14,6 @@ import { Li, Ul } from '@/design-system/typography/list' import { SmallBody } from '@/design-system/typography/paragraphs' import { targetUnitSelector } from '@/selectors/simulationSelectors' import { DottedName } from 'modele-social' -import { max } from 'ramda' import { useContext } from 'react' import { Trans, useTranslation } from 'react-i18next' import { useSelector } from 'react-redux' @@ -115,7 +114,7 @@ function Distribution() { .filter(([, value]) => value > 0) .sort(([, a], [, b]) => b - a) - const maximum = distribution.map(([, value]) => value).reduce(max, 0) + const maximum = Math.max(...distribution.map(([, value]) => value)) return ( <> diff --git a/site/source/components/utils/useSearchParamsSimulationSharing.ts b/site/source/components/utils/useSearchParamsSimulationSharing.ts index fcbac657c..31b449240 100644 --- a/site/source/components/utils/useSearchParamsSimulationSharing.ts +++ b/site/source/components/utils/useSearchParamsSimulationSharing.ts @@ -8,7 +8,6 @@ import { configSelector } from '@/selectors/simulationSelectors' import Engine, { ParsedRules, serializeEvaluation } from 'publicodes' import { DottedName } from 'modele-social' import { setActiveTarget, batchUpdateSituation } from '@/actions/actions' -import { isEmpty } from 'ramda' type Objectifs = (string | { objectifs: string[] })[] type ShortName = string @@ -44,7 +43,7 @@ export default function useSearchParamsSimulationSharing() { searchParams, dottedNameParamName ) - if (!isEmpty(newSituation)) { + if (Object.keys(newSituation).length > 0) { dispatch(batchUpdateSituation(newSituation as Situation)) } diff --git a/site/source/locales/translateRules.ts b/site/source/locales/translateRules.ts index fb773fd87..0dd0e6181 100644 --- a/site/source/locales/translateRules.ts +++ b/site/source/locales/translateRules.ts @@ -1,4 +1,3 @@ -import { assoc, mapObjIndexed } from 'ramda' import { Rule } from 'publicodes' type Translation = Record @@ -15,21 +14,17 @@ const translateSuggestion: translateAttribute = ( rule, translation, lang -) => - assoc( - 'suggestions', - Object.entries(rule.suggestions!).reduce( - (acc, [name, value]) => ({ - ...acc, - [translation[`${prop}.${name}.${lang}`]?.replace( - /^\[automatic\] /, - '' - )]: value, - }), - {} - ), - rule - ) +) => ({ + ...rule, + suggestions: Object.entries(rule.suggestions!).reduce( + (acc, [name, value]) => ({ + ...acc, + [translation[`${prop}.${name}.${lang}`]?.replace(/^\[automatic\] /, '')]: + value, + }), + {} + ), +}) export const attributesToTranslate = [ 'titre', @@ -49,7 +44,7 @@ const translateProp = let propTrans = translation[prop + '.' + lang] propTrans = propTrans?.replace(/^\[automatic\] /, '') - return propTrans ? assoc(prop, propTrans, rule) : rule + return propTrans ? { ...rule, [prop]: propTrans } : rule } function translateRule( @@ -74,13 +69,14 @@ export default function translateRules( translations: Record, rules: Record ): Record { - const translatedRules = mapObjIndexed( - (rule: Rule, name: string) => + const translatedRules = Object.fromEntries( + Object.entries(rules).map(([name, rule]) => [ + name, rule && typeof rule === 'object' ? translateRule(lang, translations, name, rule) : rule, - rules + ]) ) - return translatedRules + return translatedRules as Record } diff --git a/site/source/pages/Budget/Budget.tsx b/site/source/pages/Budget/Budget.tsx index 7ce5c36fb..debcbea7a 100644 --- a/site/source/pages/Budget/Budget.tsx +++ b/site/source/pages/Budget/Budget.tsx @@ -6,7 +6,6 @@ import { ScrollToTop } from '@/components/utils/Scroll' import { Item, Select } from '@/design-system/field/Select' import { H1, H2 } from '@/design-system/typography/heading' import { formatValue } from 'publicodes' -import { sum, uniq } from 'ramda' import { useState } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' @@ -33,17 +32,21 @@ const ressources = { 2022: ressources2022, } as const +const arraySum = (arr: number[]) => arr.reduce((a, b) => a + b, 0) + export default function Budget() { const years = ['2019', '2020', '2021', '2022'] as const const quarters = ['T1', 'T2', 'T3', 'T4'] const [selectedYear, setSelectedYear] = useState( years[years.length - 1] ) - const categories = uniq( - quarters - .map((q) => Object.keys(budget[selectedYear]?.[q] ?? {})) - .reduce((acc, curr) => [...acc, ...curr], []) - ) + const categories = [ + ...new Set( + quarters + .map((q) => Object.keys(budget[selectedYear]?.[q] ?? {})) + .reduce((acc, curr) => [...acc, ...curr], []) + ), + ] const { language } = useTranslation().i18n @@ -115,7 +118,7 @@ export default function Budget() { })} {formatValue( - sum( + arraySum( quarters.map( (q) => budget[selectedYear]?.[q]?.[label] ?? 0 ) @@ -133,7 +136,7 @@ export default function Budget() { Total HT {quarters.map((q) => { - const value = sum( + const value = arraySum( Object.values(budget[selectedYear]?.[q] ?? {}) ) @@ -150,9 +153,11 @@ export default function Budget() { })} {formatValue( - sum( + arraySum( quarters.map((q) => - sum(Object.values(budget[selectedYear]?.[q] ?? {})) + arraySum( + Object.values(budget[selectedYear]?.[q] ?? {}) + ) ) ), { @@ -166,7 +171,8 @@ export default function Budget() { Total TTC {quarters.map((q) => { const value = Math.round( - sum(Object.values(budget[selectedYear]?.[q] ?? {})) * 1.2 + arraySum(Object.values(budget[selectedYear]?.[q] ?? {})) * + 1.2 ) return ( @@ -183,10 +189,10 @@ export default function Budget() { {formatValue( Math.round( - sum( + arraySum( quarters.map( (q) => - sum( + arraySum( Object.values(budget[selectedYear]?.[q] ?? {}) ) * 1.2 ) diff --git a/site/source/pages/Creer/GuideStatut/PickLegalStatus.tsx b/site/source/pages/Creer/GuideStatut/PickLegalStatus.tsx index 2725f2ceb..c451e9966 100644 --- a/site/source/pages/Creer/GuideStatut/PickLegalStatus.tsx +++ b/site/source/pages/Creer/GuideStatut/PickLegalStatus.tsx @@ -2,7 +2,6 @@ import { SitePathsContext } from '@/components/utils/SitePathsContext' import { Button } from '@/design-system/buttons' import { H2, H3 } from '@/design-system/typography/heading' import { Body } from '@/design-system/typography/paragraphs' -import { filter } from 'ramda' import { Fragment, useContext } from 'react' import { Helmet } from 'react-helmet-async' import { Trans, useTranslation } from 'react-i18next' @@ -111,20 +110,25 @@ export default function SetMainStatus() { )} - {Object.keys(filter(Boolean, possibleStatus)).map( - /* https://github.com/microsoft/TypeScript/issues/32811 */ - (statut: any) => ( - -

    - -

    - - - - -
    - ) - )} + {Object.entries(possibleStatus) + .filter(([, v]) => Boolean(v)) + .map( + /* https://github.com/microsoft/TypeScript/issues/32811 */ + ([statut]) => ( + +

    + +

    + + + + +
    + ) + )} ) } diff --git a/site/source/pages/Creer/GuideStatut/PreviousAnswers.tsx b/site/source/pages/Creer/GuideStatut/PreviousAnswers.tsx index c989edb5b..3aad115ec 100644 --- a/site/source/pages/Creer/GuideStatut/PreviousAnswers.tsx +++ b/site/source/pages/Creer/GuideStatut/PreviousAnswers.tsx @@ -1,6 +1,5 @@ import { SitePathsContext } from '@/components/utils/SitePathsContext' import { Link } from '@/design-system/typography/link' -import { isNil } from 'ramda' import { useContext } from 'react' import { Trans } from 'react-i18next' import { useSelector } from 'react-redux' @@ -77,7 +76,7 @@ export default function PreviousAnswers() { {Object.entries(legalStatus).map( ([key, value]) => - !isNil(value) && ( + value !== undefined && ( { ) as (keyof typeof state.choixStatutJuridique.companyLegalStatus)[] ) useEffect(() => { - const companyStatusCurrentQuestionName = (toPairs( + const companyStatusCurrentQuestionName = (Object.entries( sitePaths.créer.guideStatut ).find(([, pathname]) => location.pathname === pathname) || [])[0] if (!companyStatusCurrentQuestionName) { return } - const answersToReset = dropWhile( - (a) => a !== companyStatusCurrentQuestionName, - answeredQuestion + const firstAnswerToResetIndex = answeredQuestion.findIndex( + (a) => a === companyStatusCurrentQuestionName ) - if (!answersToReset.length) { - return + + if (firstAnswerToResetIndex !== -1) { + dispatch( + resetCompanyStatusChoice( + answeredQuestion.slice(firstAnswerToResetIndex) + ) + ) } - dispatch(resetCompanyStatusChoice(answersToReset)) }, [location.pathname, dispatch, sitePaths.créer.guideStatut]) } diff --git a/site/source/pages/Simulateurs/EconomieCollaborative/ActivitésSelection.tsx b/site/source/pages/Simulateurs/EconomieCollaborative/ActivitésSelection.tsx index ade87e11a..57534db3a 100644 --- a/site/source/pages/Simulateurs/EconomieCollaborative/ActivitésSelection.tsx +++ b/site/source/pages/Simulateurs/EconomieCollaborative/ActivitésSelection.tsx @@ -5,7 +5,6 @@ import { ScrollToTop } from '@/components/utils/Scroll' import { Spacing } from '@/design-system/layout' import { H1, H2 } from '@/design-system/typography/heading' import { Body, SmallBody } from '@/design-system/typography/paragraphs' -import { intersection } from 'ramda' import { useContext } from 'react' import { Trans, useTranslation } from 'react-i18next' import { TrackPage } from '../../../ATInternetTracking' @@ -90,10 +89,9 @@ export const ActivitéSelection = ({ }: ActivitéSelectionProps) => { const { state } = useContext(StoreContext) const activitéRépondue = activitésRéponduesSelector(state) - const nextButtonDisabled = !intersection( - activitésEffectuéesSelector(state), - activités - ).length + const nextButtonDisabled = activitésEffectuéesSelector(state).every( + (a) => !activités.includes(a) + ) return ( <> diff --git a/site/source/pages/Stats/SatisfactionChart.tsx b/site/source/pages/Stats/SatisfactionChart.tsx index 22a0a157c..4202b7876 100644 --- a/site/source/pages/Stats/SatisfactionChart.tsx +++ b/site/source/pages/Stats/SatisfactionChart.tsx @@ -3,7 +3,6 @@ import Emoji from '@/components/utils/Emoji' import { Strong } from '@/design-system/typography' import { Li, Ul } from '@/design-system/typography/list' import { Body } from '@/design-system/typography/paragraphs' -import { add, mapObjIndexed } from 'ramda' import { Bar, BarChart, @@ -25,9 +24,11 @@ export const SatisfactionStyle: [ ] function toPercentage(data: Record): Record { - const total = Object.values(data).reduce(add) + const total = Object.values(data).reduce((a, b: number) => a + b, 0) - return { ...mapObjIndexed((value) => (100 * value) / total, data), total } + return Object.fromEntries( + Object.entries(data).map(([key, value]) => [key, (100 * value) / total]) + ) } type SatisfactionChartProps = { diff --git a/site/source/pages/Stats/Stats.tsx b/site/source/pages/Stats/Stats.tsx index 19509de88..b321975ae 100644 --- a/site/source/pages/Stats/Stats.tsx +++ b/site/source/pages/Stats/Stats.tsx @@ -8,7 +8,7 @@ import { Item, Select } from '@/design-system/field/Select' import { Spacing } from '@/design-system/layout' import { H2, H3 } from '@/design-system/typography/heading' import { formatValue } from 'publicodes' -import { add, groupBy, mapObjIndexed, mergeWith, toPairs } from 'ramda' +import { add, groupBy, mapObjIndexed, mergeWith } from 'ramda' import { useCallback, useEffect, useMemo, useState } from 'react' import { Trans } from 'react-i18next' import { useHistory, useLocation } from 'react-router-dom' @@ -46,7 +46,7 @@ const isPAM = (name: string | undefined) => ].includes(name) const filterByChapter2 = (pages: Pageish[], chapter2: Chapter2 | '') => { - return toPairs( + return Object.entries( groupBy( (p) => ('date' in p ? p.date : p.month), pages.filter( @@ -67,7 +67,7 @@ const filterByChapter2 = (pages: Pageish[], chapter2: Chapter2 | '') => { } function groupByDate(data: Pageish[]) { - return toPairs( + return Object.entries( groupBy( (p) => ('date' in p ? p.date : p.month), data.filter((d) => 'page' in d && d.page === 'accueil') diff --git a/site/source/pages/gerer/demande-mobilité/index.tsx b/site/source/pages/gerer/demande-mobilité/index.tsx index 2fad2074a..0d554f154 100644 --- a/site/source/pages/gerer/demande-mobilité/index.tsx +++ b/site/source/pages/gerer/demande-mobilité/index.tsx @@ -10,11 +10,10 @@ import { Button } from '@/design-system/buttons' import { Spacing } from '@/design-system/layout' import { headings } from '@/design-system/typography' import { Intro, SmallBody } from '@/design-system/typography/paragraphs' -import { evaluateQuestion, hash } from '@/utils' +import { evaluateQuestion, hash, omit } from '@/utils' import { Grid } from '@mui/material' import { DottedName } from 'modele-social' import Engine, { PublicodesExpression } from 'publicodes' -import { omit } from 'ramda' import { Fragment, lazy, @@ -80,7 +79,7 @@ function FormulairePublicodes() { const onChange = useCallback( (dottedName, value) => { if (value === undefined) { - setSituation((situation) => omit([dottedName], situation)) + setSituation((situation) => omit(situation, dottedName)) } else { setSituation((situation) => ({ ...situation, diff --git a/site/source/reducers/rootReducer.ts b/site/source/reducers/rootReducer.ts index e1c5d3e80..17be2d1ff 100644 --- a/site/source/reducers/rootReducer.ts +++ b/site/source/reducers/rootReducer.ts @@ -2,7 +2,6 @@ import { Action } from '@/actions/actions' import { Commune } from '@/api/commune' import { PreviousSimulation } from '@/selectors/previousSimulationSelectors' import { DottedName } from 'modele-social' -import { defaultTo, without } from 'ramda' import reduceReducers from 'reduce-reducers' import { combineReducers, Reducer } from 'redux' import { objectifsSelector } from '../selectors/simulationSelectors' @@ -114,17 +113,16 @@ function simulation( } case 'UPDATE_SITUATION': { - const objectifs = without( - ['entreprise . charges'], - objectifsSelector({ simulation: state } as RootState) - ) + const objectifs = objectifsSelector({ + simulation: state, + } as RootState).filter((name) => name !== 'entreprise . charges') const situation = state.situation const { fieldName: dottedName, value } = action if (value === undefined) { return { ...state, situation: omit(situation, dottedName) } } if (objectifs.includes(dottedName)) { - const objectifsToReset = without([dottedName], objectifs) + const objectifsToReset = objectifs.filter((name) => name !== dottedName) const newSituation = Object.fromEntries( Object.entries(situation).filter( ([dottedName]) => @@ -160,7 +158,7 @@ function simulation( if (name === 'unfold') { return { ...state, - foldedSteps: without([step], state.foldedSteps), + foldedSteps: state.foldedSteps.filter((name) => name !== step), unfoldedStep: step, } } @@ -197,7 +195,7 @@ const mainReducer = combineReducers({ explainedVariable, simulation, companySituation, - previousSimulation: defaultTo(null) as Reducer, + previousSimulation: ((p) => p ?? null) as Reducer, activeTargetInput, choixStatutJuridique, }) diff --git a/site/source/selectors/previousSimulationSelectors.ts b/site/source/selectors/previousSimulationSelectors.ts index c8c71297c..53768d642 100644 --- a/site/source/selectors/previousSimulationSelectors.ts +++ b/site/source/selectors/previousSimulationSelectors.ts @@ -3,7 +3,7 @@ import { DottedName } from 'modele-social' export type PreviousSimulation = { situation: Simulation['situation'] - activeTargetInput: RootState['activeTargetInput'] + activeTargetInput: DottedName | null foldedSteps: Array | undefined } diff --git a/site/source/sitePaths.ts b/site/source/sitePaths.ts index ba5aea76d..11542bc12 100644 --- a/site/source/sitePaths.ts +++ b/site/source/sitePaths.ts @@ -1,5 +1,4 @@ import { MetadataSrc } from 'pages/Simulateurs/metadata-src' -import { reduce, toPairs, zipObj } from 'ramda' import { LegalStatus } from '@/selectors/companyStatusSelectors' export const LANDING_LEGAL_STATUS_LIST: Array = [ @@ -235,13 +234,12 @@ export const constructLocalizedSitePath = (language: 'en' | 'fr') => { export type SitePathsType = ReturnType const deepReduce = (fn: any, initialValue?: any, object?: any): any => - reduce( + Object.entries(object).reduce( (acc, [key, value]) => typeof value === 'object' ? deepReduce(fn, acc, value) : fn(acc, value, key), - initialValue, - toPairs(object) + initialValue ) type SiteMap = Array @@ -271,12 +269,10 @@ const frSiteMap = generateSiteMap(constructLocalizedSitePath('fr')).map( ) export const hrefLangLink = { - en: zipObj( - enSiteMap, - frSiteMap.map((href) => [{ href, hrefLang: 'fr' }]) + en: Object.fromEntries( + enSiteMap.map((key, i) => [key, { href: frSiteMap[i], hrefLang: 'fr' }]) ), - fr: zipObj( - frSiteMap, - enSiteMap.map((href) => [{ href, hrefLang: 'en' }]) + fr: Object.fromEntries( + frSiteMap.map((key, i) => [key, { href: enSiteMap[i], hrefLang: 'en' }]) ), } diff --git a/site/source/storage/persistSimulation.ts b/site/source/storage/persistSimulation.ts index 80e05df7f..4f5780673 100644 --- a/site/source/storage/persistSimulation.ts +++ b/site/source/storage/persistSimulation.ts @@ -1,7 +1,6 @@ import { Action } from '@/actions/actions' import { RootState } from '@/reducers/rootReducer' import { PreviousSimulation } from '@/selectors/previousSimulationSelectors' -import { isEmpty } from 'ramda' import { Store } from 'redux' import { debounce } from '../utils' import * as safeLocalStorage from './safeLocalStorage' @@ -21,7 +20,7 @@ export function setupSimulationPersistence( if (!state.simulation?.url) { return } - if (isEmpty(state.simulation?.situation)) { + if (Object.keys(state.simulation?.situation).length === 0) { return } safeLocalStorage.setItem( diff --git a/site/source/storage/serializeSimulation.ts b/site/source/storage/serializeSimulation.ts index 8293dc928..82c9582df 100644 --- a/site/source/storage/serializeSimulation.ts +++ b/site/source/storage/serializeSimulation.ts @@ -1,6 +1,7 @@ -import { pipe } from 'ramda' import { currentSimulationSelector } from '@/selectors/previousSimulationSelectors' -export const serialize = pipe(currentSimulationSelector, JSON.stringify) +export const serialize = ( + ...args: Parameters +) => JSON.stringify(currentSimulationSelector(...args)) export const deserialize = JSON.parse diff --git a/site/source/utils.ts b/site/source/utils.ts index e107bd38e..52511a6e5 100644 --- a/site/source/utils.ts +++ b/site/source/utils.ts @@ -77,8 +77,7 @@ export function hash(str: string): number { } export function omit(obj: T, key: K): Omit { - const returnObject = { ...obj } - delete returnObject[key] + const { [key]: _ignore, ...returnObject } = obj return returnObject } diff --git a/site/test/unit-translations.test.js b/site/test/unit-translations.test.js index 66b135247..3a55b5a47 100644 --- a/site/test/unit-translations.test.js +++ b/site/test/unit-translations.test.js @@ -1,22 +1,23 @@ import { it, expect, describe } from 'vitest' import { parsePublicodes } from 'publicodes' -import { uniq } from 'ramda' import rawRules from 'modele-social' import unitsTranslations from '../source/locales/units.yaml' describe('Tests units', function () { it('use unit that exists in publicodes', function () { const { parsedRules } = parsePublicodes(rawRules) - const units = uniq( - Object.keys(parsedRules).reduce( - (prev, name) => [ - ...prev, - ...(parsedRules[name].unit?.numerators ?? []), - ...(parsedRules[name].unit?.denumerators ?? []), - ], - [] - ) - ) + const units = [ + ...new Set( + Object.keys(parsedRules).reduce( + (prev, name) => [ + ...prev, + ...(parsedRules[name].unit?.numerators ?? []), + ...(parsedRules[name].unit?.denumerators ?? []), + ], + [] + ) + ), + ] const blackList = ['€', '%'] const translatedKeys = Object.keys(unitsTranslations.en)