Skip to content

Update Transition, upgrade packages and fix compilation issues arising from it#1378

Merged
tahini merged 3 commits intochairemobilite:mainfrom
tahini:updateTransition
Jan 28, 2026
Merged

Update Transition, upgrade packages and fix compilation issues arising from it#1378
tahini merged 3 commits intochairemobilite:mainfrom
tahini:updateTransition

Conversation

@tahini
Copy link
Contributor

@tahini tahini commented Jan 27, 2026

  • Use widgets from chaire-lib for the inputMap's select and inputRange's NA checkbox, as the fake evolution widget with incomplete types cause compilation errors.

  • Define the Filter type in InterviewList instead of its caller InterviewListComponent, as otherwise, it is unknown in the list and requires compilation gymnastic, while we know the exact type.

  • Update Transition and various packages to match the update: react & cie, i18next and related:

  • The Markdown component does not take a className anymore, so the
    class needs to be added manually to a parent div. Update snapshots
    accordingly.

  • The update the chaire-lib's bcrypt package changed the format of
    password hash, so the participantAuthModel.test.ts needed updating.

Summary by CodeRabbit

  • Chores

    • Updated dependencies across the project, including React, React Router, date-fns, i18next, and testing libraries to latest compatible versions for improved performance and stability.
  • Bug Fixes

    • Fixed authentication hash compatibility to ensure secure credential handling.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 27, 2026

Walkthrough

This PR updates dependencies across the monorepo (i18next, React, react-i18next, and others), refactors i18n integration from withTranslation HOCs to useTranslation hooks in multiple components (InterviewList, InputRange, Button), exports the Filter type from InterviewList for reuse, updates DOM structures around Markdown components, changes locale imports in InputDatePicker, and updates component tests with new fixtures and navigation mocks. A bcrypt hash prefix test expectation is also updated.

Possibly related PRs

Suggested reviewers

  • kaligrafy
  • samuel-duhaime
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main changes: updating the Transition submodule, upgrading multiple packages, and addressing resulting compilation issues.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/evolution-frontend/src/components/inputs/__tests__/InputMapFindPlace.test.tsx (1)

184-189: Update the stale comment to match the new option count.

The comment still says 4 children, but the assertion now expects 3. Please align the comment to avoid confusion.

Suggested fix
-        // The select list should display 4 children (2 places and the 2 extra elements) and should not have a confirm button
+        // The select list should display 3 children (2 places + empty choice) and should not have a confirm button
🤖 Fix all issues with AI agents
In
`@packages/evolution-frontend/src/components/admin/validations/InterviewList.tsx`:
- Around line 145-147: The button in InterviewList.tsx that renders <button
title={t('admin:HideInterviewList')} onClick={() =>
props.interviewListChange(false)}> (which contains FontAwesomeIcon and faFolder
and calls props.interviewListChange) needs an explicit type to avoid being
treated as a form submit button; change the element to include type="button" so
clicking it only triggers the onClick handler and does not submit any parent
form.

In
`@packages/evolution-frontend/src/components/admin/validations/ValidationAuditFilter.tsx`:
- Around line 146-152: Keep the temporary 'as any' cast but clarify the FIXME by
turning it into a TODO that indicates this is an intentional short-term
workaround and that the long-term fix is to type the select styles using
react-select's StylesConfig; specifically update the comment above the option
style function (the option: (baseStyles, _state) => ({...}) as any) to state
it's deliberate for now and reference StylesConfig as the target for future
typing cleanup.

Comment on lines +145 to 147
<button title={t('admin:HideInterviewList')} onClick={() => props.interviewListChange(false)}>
<FontAwesomeIcon icon={faFolder} />
</button>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add explicit type="button" to prevent unintended form submission.

Without an explicit type, buttons default to type="submit".

Proposed fix
-                <button title={t('admin:HideInterviewList')} onClick={() => props.interviewListChange(false)}>
+                <button type="button" title={t('admin:HideInterviewList')} onClick={() => props.interviewListChange(false)}>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<button title={t('admin:HideInterviewList')} onClick={() => props.interviewListChange(false)}>
<FontAwesomeIcon icon={faFolder} />
</button>
<button type="button" title={t('admin:HideInterviewList')} onClick={() => props.interviewListChange(false)}>
<FontAwesomeIcon icon={faFolder} />
</button>
🧰 Tools
🪛 Biome (2.1.2)

[error] 145-145: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

🤖 Prompt for AI Agents
In
`@packages/evolution-frontend/src/components/admin/validations/InterviewList.tsx`
around lines 145 - 147, The button in InterviewList.tsx that renders <button
title={t('admin:HideInterviewList')} onClick={() =>
props.interviewListChange(false)}> (which contains FontAwesomeIcon and faFolder
and calls props.interviewListChange) needs an explicit type to avoid being
treated as a form submit button; change the element to include type="button" so
clicking it only triggers the onClick handler and does not submit any parent
form.

Comment on lines +146 to +152
// FIXME Remove the need for 'as any' by typing the styles properly. But there is compilation error even though it should be correct.
option: (baseStyles, _state) =>
({
...baseStyles,
paddingTop: 0,
paddingBottom: 0
}) as any
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🏁 Script executed:

cat -n packages/evolution-frontend/src/components/admin/validations/ValidationAuditFilter.tsx | sed -n '140,160p'

Repository: chairemobilite/evolution

Length of output: 1322


🌐 Web query:

react-select v5 StylesConfig type definition

💡 Result:

In react-select v5, StylesConfig is defined (in src/styles.d.ts) as:

export type StylesConfig<
  Option = unknown,
  IsMulti extends boolean = boolean,
  Group extends GroupBase<Option> = GroupBase<Option>
> = {
  [K in keyof StylesProps<Option, IsMulti, Group>]?: (
    base: CSSObjectWithLabel,
    props: StylesProps<Option, IsMulti, Group>[K]
  ) => CSSObjectWithLabel;
};

[1]

It’s exported from the package entry so you can use it as:

import type { StylesConfig } from "react-select";

[2]


The as any cast is a reasonable temporary workaround.

The FIXME comment properly documents this technical debt. When you have time to revisit, consider typing the styles prop with react-select's StylesConfig type for proper type safety.

🤖 Prompt for AI Agents
In
`@packages/evolution-frontend/src/components/admin/validations/ValidationAuditFilter.tsx`
around lines 146 - 152, Keep the temporary 'as any' cast but clarify the FIXME
by turning it into a TODO that indicates this is an intentional short-term
workaround and that the long-term fix is to type the select styles using
react-select's StylesConfig; specifically update the comment above the option
style function (the option: (baseStyles, _state) => ({...}) as any) to state
it's deliberate for now and reference StylesConfig as the target for future
typing cleanup.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 27 files

Copy link
Collaborator

@samuel-duhaime samuel-duhaime left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I accept, but make sure we haven't broken anything with Playwright and fix the unit test.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tahini Can you verify if survey-question__input (and other new term) was used with the Playwright test UI? So we don't break anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UI tests are not broken

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Fix all issues with AI agents
In `@example/demo_survey/package.json`:
- Around line 47-49: The package.json dependency versions may be incompatible or
require config changes: verify that i18next >= 25.6.2 is present (add it if
missing) to satisfy react-i18next@16.5.3; review and, if your app submits
cross-origin actions, update react-router configuration (see
react-router.config.ts) to include allowedActionOrigins to permit
external-origin submissions for react-router@7.12.0; audit code for React 19.2
breaking changes (hooks useId prefix, eslint-plugin-react-hooks@6, SSR/Suspense
batching) and, if using React Server Components, bump React to 19.2.4+ (change
the "react" entry) to get the RSC security fixes.

In
`@packages/evolution-frontend/src/components/inputs/__tests__/InputRange.test.tsx`:
- Around line 29-45: The mock MockInputCheckbox currently hardcodes the emitted
value and assumes choices[0] exists; update the mock so it reads the actual
choice value and guards against empty choices: in the mock function
(MockInputCheckbox) derive a safeChoiceValue = choices && choices.length ?
choices[0].value : 'true' (or ''), set the input value to safeChoiceValue, set
checked to Array.isArray(value) ? value.includes(safeChoiceValue) : false, and
onChange call onValueChange({ target: { value: e.target.checked ?
[safeChoiceValue] : [] } }) so snapshots reflect real choice values and the mock
won’t crash when choices is empty.

In `@packages/evolution-frontend/src/components/survey/__tests__/Button.test.tsx`:
- Around line 22-35: The mocked ConfirmModal's buttons in MockConfirmModal do
not have explicit type attributes which can trigger linter/warning issues;
update the mock defined in the jest.mock callback (the MockConfirmModal
function) to add type="button" to both the cancel and confirm buttons (the
elements invoking props.cancelAction/props.confirmAction and using
props.cancelButtonLabel/props.confirmButtonLabel) so they are explicit
non-submit buttons in tests.

In
`@packages/evolution-frontend/src/components/survey/__tests__/GroupWidgets.test.tsx`:
- Around line 23-36: The mock ConfirmModal implementation (MockConfirmModal)
renders two buttons without an explicit type which triggers linter warnings;
update the mock in GroupWidgets.test.tsx so both button elements include
type="button" (the cancel and confirm buttons rendered with
props.cancelAction/props.confirmAction) to match Button.test.tsx and silence the
warnings.

In
`@packages/evolution-frontend/src/components/survey/widgets/__tests__/DeleteGroupedObjectButton.test.tsx`:
- Around line 18-28: The mocked ConfirmModal function (MockConfirmModal) renders
two buttons that currently lack explicit types; update the mock so both button
elements that call props.cancelAction and props.confirmAction include
type="button" to avoid default submit behavior and satisfy lint/a11y rules,
keeping the rest of the mock structure unchanged.

In `@packages/evolution-generator/package.json`:
- Line 31: Three components (RefreshInterviewerCache, ExportInterviewData,
InterviewsPage) still use the withTranslation HOC; convert each to the
useTranslation hook: remove the import and use of withTranslation and any
WithTranslation prop types, add import { useTranslation } from 'react-i18next',
call const { t } = useTranslation() at the top of the component body (or const {
t } = useTranslation('yourNamespace') if a namespace was used before), replace
all occurrences of props.t or this.props.t with t, and change the export to the
plain component (no HOC wrap). Ensure prop interfaces are updated to drop
WithTranslation and the components remain function components or are converted
from wrapped declarations accordingly.

Comment on lines +47 to +49
"react": "^19.2.3",
"react-i18next": "^16.5.3",
"react-router": "^7.12.0",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

React 19.2.3 peer dependencies requirements breaking changes

💡 Result:

Peer dependency requirements (React 19.2.3 era)

  • react@19.2.3

    • Peer deps: none (the react package declares no peerDependencies). [1]
  • react-dom@19.2.x

    • Peer deps: react (React DOM expects React to be kept in sync). For example, react-dom@19.2.2 declares peerDependencies: { "react": "^19.2.2" } (and 19.2.3 follows the same “same-version caret” pairing pattern). [2]
  • If you use React Server Components packages (common via frameworks)

    • react-server-dom-webpack@19.2.3 peer deps: react@^19.2.3, react-dom@^19.2.3, and webpack@^5.59.0. [3]
    • (Similar peer-dep coupling applies to the other react-server-dom-* packages.)

Breaking changes

  • 19.2.3 itself (patch release): no intentional breaking changes; it’s a patch with a small React Server Components fix (“extra loop protection to React Server Functions”). [4]

  • Breaking / notable behavior changes come from React 19.2 (minor release), not 19.2.3:

    • React 19.2’s “Notable Changes” include SSR/Suspense batching changes, Node Web Streams support for SSR, eslint-plugin-react-hooks v6, and an update to the default useId prefix. [5]

Important caveat (security / “upgrade again” note)

  • If you’re using React Server Components packages (react-server-dom-webpack / -parcel / -turbopack), React’s security guidance (updated Jan 26, 2026) says that 19.2.3 is incomplete for the then-current RSC vulnerabilities, and you should upgrade to the fixed backport 19.2.4 (or newer) for those packages. [6]

Sources:
[1] react@19.2.3 package.json (UNPKG)
[2] react-dom@19.2.2 package.json (UNPKG)
[3] react-server-dom-webpack@19.2.3 package.json (UNPKG)
[4] facebook/react v19.2.3 release notes (GitHub)
[5] React 19.2 blog post (react.dev)
[6] RSC vulnerabilities + upgrade guidance (react.dev, updated Jan 26, 2026)


🌐 Web query:

react-i18next 16.5.3 peer dependencies requirements breaking changes

💡 Result:

react-i18next 16.5.3 peer dependency requirements

From the v16.5.x package manifest, react-i18next expects these peers (TypeScript is optional, but required for type-checking the library’s .d.ts/.d.mts cleanly):

  • react: >= 16.8.0
  • i18next: >= 25.6.2
  • typescript: ^5 (optional peer)
  • react-dom: optional peer
  • react-native: optional peer  [1]

Breaking changes / upgrade impact

In 16.5.3 itself

  • No breaking changes; it’s a patch release with: “fix: Trans named tags with underscore”. [2]

When upgrading to v16.x (relevant “breaking-ish” changes vs older majors)

  • Higher required i18next: you may need to upgrade i18next to >= 25.6.2 to satisfy peer deps. [1]
  • TypeScript 5 expectation: v16.x declares TS ^5 as a (optional) peer; this aligns with upstream i18next type patterns that aren’t compatible with TS4-era tooling. [1][3]

Sources: [1] package.json (v16.5.x) via UNPKG, [2] v16.5.3 changelog entry, [3] upstream i18next TypeScript 4 incompatibility discussion.


🌐 Web query:

react-router 7.12.0 peer dependencies breaking changes compatibility

💡 Result:

Peer dependencies / engines in react-router / react-router-dom 7.12.0

  • React: >=18
  • react-dom: >=18 (for react-router-dom; and is a peer for react-router as well)
  • Node: >=20 (engine requirement)
    These constraints are shown directly in the react-router-dom@7.12.0 package.json, which depends on react-router@7.12.0. [1] React Router’s upgrade docs also state v7 requires node@20, react@18, react-dom@18. [2]

Compatibility note: Because the peer range is >=18, React Router 7.12.0 is compatible with React 18 and React 19, assuming the rest of your dependency tree allows it. [1]

Breaking/behavior changes called out for 7.12.0

7.12.0 is primarily a security release, but it includes a potentially breaking behavior change if your app relies on cross-origin submissions to “UI routes”:

  • React Router now rejects submissions to UI routes from external origins as an additional CSRF protection layer. [3]
  • If you intentionally need to allow specific external origins, you must configure the new allowedActionOrigins field in react-router.config.ts. [3]

Common “peer dependency conflict” you may be seeing

If a third-party package declares peers like react-router: "7" (or similar), you cannot satisfy it with react-router-dom@6.x; npm will report a peer conflict until you upgrade to v7 or the library broadens its peer range. (Example of this class of issue: a library requiring react-router: "7" while the app is still on react-router-dom@6.) [4]

Sources: [1] [2] [3] [4]


Confirm i18next version and review breaking changes for React & Router.

  1. react-i18next 16.5.3 requires i18next ≥ 25.6.2—verify this dependency is present.
  2. react-router 7.12.0 introduces CSRF protection that rejects external-origin submissions to UI routes. If needed, add allowedActionOrigins config in react-router.config.ts.
  3. React 19.2 includes breaking changes: useId prefix update, eslint-plugin-react-hooks@6, and SSR/Suspense batching. Review app impact.
  4. If using React Server Components, upgrade React to 19.2.4+ (19.2.3 has incomplete RSC security fixes).
🤖 Prompt for AI Agents
In `@example/demo_survey/package.json` around lines 47 - 49, The package.json
dependency versions may be incompatible or require config changes: verify that
i18next >= 25.6.2 is present (add it if missing) to satisfy
react-i18next@16.5.3; review and, if your app submits cross-origin actions,
update react-router configuration (see react-router.config.ts) to include
allowedActionOrigins to permit external-origin submissions for
react-router@7.12.0; audit code for React 19.2 breaking changes (hooks useId
prefix, eslint-plugin-react-hooks@6, SSR/Suspense batching) and, if using React
Server Components, bump React to 19.2.4+ (change the "react" entry) to get the
RSC security fixes.

Comment on lines 29 to 45
// Mock the InputCheckbox component, as it uses many react hooks and libraries that make jest fail. For this component, the checkbox will contain only one choice
jest.mock('chaire-lib-frontend/lib/components/input/InputCheckbox', () => {
return function MockInputCheckbox({ id, value, onValueChange, choices }: any) {
return (
<div data-testid={`mock-checkbox-${id}`}>
<input
type="checkbox"
id={id}
checked={value && value.length > 0}
value={choices[0].value}
onChange={(e) => onValueChange({ target: { value: e.target.checked ? ['true'] : [] } })}
/>
<label htmlFor={id}>{choices[0].label}</label>
</div>
);
}
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Mock returns a hardcoded value; this can hide regressions.

onValueChange always emits ['true'] and assumes choices[0] exists. If the real component uses the choice value (e.g., 'na'), snapshots won’t reflect mismatches and the mock may crash when choices is empty. Consider aligning the mock to the actual choice value and guarding against empty choices.

✅ Suggested fix
-    return function MockInputCheckbox({ id, value, onValueChange, choices }: any) {
+    return function MockInputCheckbox({ id, value, onValueChange, choices }: any) {
+        const firstChoice = choices?.[0];
+        if (!firstChoice) {
+            return null;
+        }
         return (
             <div data-testid={`mock-checkbox-${id}`}>
                 <input
                     type="checkbox"
                     id={id}
-                    checked={value && value.length > 0}
-                    value={choices[0].value}
-                    onChange={(e) => onValueChange({ target: { value: e.target.checked ? ['true'] : [] } })}
+                    checked={Array.isArray(value) ? value.includes(firstChoice.value) : value === firstChoice.value}
+                    value={firstChoice.value}
+                    onChange={(e) =>
+                        onValueChange({ target: { value: e.target.checked ? [firstChoice.value] : [] } })
+                    }
                 />
-                <label htmlFor={id}>{choices[0].label}</label>
+                <label htmlFor={id}>{firstChoice.label}</label>
             </div>
         );
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Mock the InputCheckbox component, as it uses many react hooks and libraries that make jest fail. For this component, the checkbox will contain only one choice
jest.mock('chaire-lib-frontend/lib/components/input/InputCheckbox', () => {
return function MockInputCheckbox({ id, value, onValueChange, choices }: any) {
return (
<div data-testid={`mock-checkbox-${id}`}>
<input
type="checkbox"
id={id}
checked={value && value.length > 0}
value={choices[0].value}
onChange={(e) => onValueChange({ target: { value: e.target.checked ? ['true'] : [] } })}
/>
<label htmlFor={id}>{choices[0].label}</label>
</div>
);
}
});
// Mock the InputCheckbox component, as it uses many react hooks and libraries that make jest fail. For this component, the checkbox will contain only one choice
jest.mock('chaire-lib-frontend/lib/components/input/InputCheckbox', () => {
return function MockInputCheckbox({ id, value, onValueChange, choices }: any) {
const firstChoice = choices?.[0];
if (!firstChoice) {
return null;
}
return (
<div data-testid={`mock-checkbox-${id}`}>
<input
type="checkbox"
id={id}
checked={Array.isArray(value) ? value.includes(firstChoice.value) : value === firstChoice.value}
value={firstChoice.value}
onChange={(e) =>
onValueChange({ target: { value: e.target.checked ? [firstChoice.value] : [] } })
}
/>
<label htmlFor={id}>{firstChoice.label}</label>
</div>
);
}
});
🤖 Prompt for AI Agents
In
`@packages/evolution-frontend/src/components/inputs/__tests__/InputRange.test.tsx`
around lines 29 - 45, The mock MockInputCheckbox currently hardcodes the emitted
value and assumes choices[0] exists; update the mock so it reads the actual
choice value and guards against empty choices: in the mock function
(MockInputCheckbox) derive a safeChoiceValue = choices && choices.length ?
choices[0].value : 'true' (or ''), set the input value to safeChoiceValue, set
checked to Array.isArray(value) ? value.includes(safeChoiceValue) : false, and
onChange call onValueChange({ target: { value: e.target.checked ?
[safeChoiceValue] : [] } }) so snapshots reflect real choice values and the mock
won’t crash when choices is empty.

Comment on lines 22 to 35
// Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail
jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => {
return function MockConfirmModal(props: any) {
if (!props.isOpen) return null;
return (
<div role="dialog" aria-label={props.title}>
<div>{props.title}</div>
<div>{props.text}</div>
<button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
<button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
</div>
);
};
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Add explicit type="button" to mock buttons.

The mock buttons lack explicit type attributes. While this is test code, adding them ensures consistency and silences linter warnings.

Proposed fix
 jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => {
     return function MockConfirmModal(props: any) {
         if (!props.isOpen) return null;
         return (
             <div role="dialog" aria-label={props.title}>
                 <div>{props.title}</div>
                 <div>{props.text}</div>
-                <button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
-                <button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
+                <button type="button" onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
+                <button type="button" onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
             </div>
         );
     };
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail
jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => {
return function MockConfirmModal(props: any) {
if (!props.isOpen) return null;
return (
<div role="dialog" aria-label={props.title}>
<div>{props.title}</div>
<div>{props.text}</div>
<button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
<button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
</div>
);
};
});
// Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail
jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => {
return function MockConfirmModal(props: any) {
if (!props.isOpen) return null;
return (
<div role="dialog" aria-label={props.title}>
<div>{props.title}</div>
<div>{props.text}</div>
<button type="button" onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
<button type="button" onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
</div>
);
};
});
🧰 Tools
🪛 Biome (2.1.2)

[error] 30-30: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 31-31: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

🤖 Prompt for AI Agents
In `@packages/evolution-frontend/src/components/survey/__tests__/Button.test.tsx`
around lines 22 - 35, The mocked ConfirmModal's buttons in MockConfirmModal do
not have explicit type attributes which can trigger linter/warning issues;
update the mock defined in the jest.mock callback (the MockConfirmModal
function) to add type="button" to both the cancel and confirm buttons (the
elements invoking props.cancelAction/props.confirmAction and using
props.cancelButtonLabel/props.confirmButtonLabel) so they are explicit
non-submit buttons in tests.

Comment on lines 23 to 36
// Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail
jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => {
return function MockConfirmModal(props: any) {
if (!props.isOpen) return null;
return (
<div role="dialog" aria-label={props.title}>
<div>{props.title}</div>
<div>{props.text}</div>
<button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
<button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
</div>
);
};
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Add explicit type="button" to mock buttons.

Same issue as in Button.test.tsx. Adding type="button" improves consistency and silences linter warnings.

Proposed fix
 jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => {
     return function MockConfirmModal(props: any) {
         if (!props.isOpen) return null;
         return (
             <div role="dialog" aria-label={props.title}>
                 <div>{props.title}</div>
                 <div>{props.text}</div>
-                <button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
-                <button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
+                <button type="button" onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
+                <button type="button" onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
             </div>
         );
     };
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail
jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => {
return function MockConfirmModal(props: any) {
if (!props.isOpen) return null;
return (
<div role="dialog" aria-label={props.title}>
<div>{props.title}</div>
<div>{props.text}</div>
<button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
<button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
</div>
);
};
});
// Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail
jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => {
return function MockConfirmModal(props: any) {
if (!props.isOpen) return null;
return (
<div role="dialog" aria-label={props.title}>
<div>{props.title}</div>
<div>{props.text}</div>
<button type="button" onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
<button type="button" onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
</div>
);
};
});
🧰 Tools
🪛 Biome (2.1.2)

[error] 31-31: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 32-32: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

🤖 Prompt for AI Agents
In
`@packages/evolution-frontend/src/components/survey/__tests__/GroupWidgets.test.tsx`
around lines 23 - 36, The mock ConfirmModal implementation (MockConfirmModal)
renders two buttons without an explicit type which triggers linter warnings;
update the mock in GroupWidgets.test.tsx so both button elements include
type="button" (the cancel and confirm buttons rendered with
props.cancelAction/props.confirmAction) to match Button.test.tsx and silence the
warnings.

Comment on lines 18 to 28
// Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail
jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => {
return function MockConfirmModal(props: any) {
if (!props.isOpen) return null;
return (
<div role="dialog" aria-label={props.title}>
<div>{props.title}</div>
<div>{props.text}</div>
<button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
<button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
</div>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add explicit type="button" to mock buttons to satisfy lint/a11y.
This avoids default submit behavior and clears the lint error.

Proposed fix
-                <button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
-                <button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
+                <button type="button" onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
+                <button type="button" onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail
jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => {
return function MockConfirmModal(props: any) {
if (!props.isOpen) return null;
return (
<div role="dialog" aria-label={props.title}>
<div>{props.title}</div>
<div>{props.text}</div>
<button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
<button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
</div>
// Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail
jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => {
return function MockConfirmModal(props: any) {
if (!props.isOpen) return null;
return (
<div role="dialog" aria-label={props.title}>
<div>{props.title}</div>
<div>{props.text}</div>
<button type="button" onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
<button type="button" onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
</div>
🧰 Tools
🪛 Biome (2.1.2)

[error] 26-26: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)


[error] 27-27: Provide an explicit type prop for the button element.

The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset

(lint/a11y/useButtonType)

🤖 Prompt for AI Agents
In
`@packages/evolution-frontend/src/components/survey/widgets/__tests__/DeleteGroupedObjectButton.test.tsx`
around lines 18 - 28, The mocked ConfirmModal function (MockConfirmModal)
renders two buttons that currently lack explicit types; update the mock so both
button elements that call props.cancelAction and props.confirmAction include
type="button" to avoid default submit behavior and satisfy lint/a11y rules,
keeping the rest of the mock structure unchanged.

"evolution-common": "^0.5.0",
"evolution-frontend": "^0.5.0",
"i18next": "^24.0.2"
"i18next": "^25.7.4"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

i18next v25 breaking changes migration guide

💡 Result:

i18next v25: breaking changes + migration notes (from v24 → v25)

Potentially breaking changes in v25.0.0

  1. Multiple changeLanguage() calls are handled in the correct order now
    If your app relied (intentionally or accidentally) on the previous wrong ordering (race behavior), you may see different final language / event timing. Re-test any flows that can trigger rapid consecutive language changes (startup, route changes, auth redirects, etc.). [1][2]

  2. changeLanguage() now always resolves languages via getBestMatchFromCodes (whether you pass a string or an array)
    This can change which language ultimately gets chosen in some setups (especially with region/script variants). [1][2]

  3. getBestMatchFromCodes now tries to fall back to a language code with the same script
    If you have script-specific locales (e.g., zh-Hans, zh-Hant), matching/fallback behavior may differ vs v24. Validate that the resolved language still matches your expectations. [1][2]

Recommended migration checklist

  • Search your codebase for all changeLanguage( call sites; add/adjust guards/debouncing if multiple calls can happen close together, and update tests around “final language wins” behavior. [1][2]
  • Verify language matching for your supported locales (especially script/region variants) by testing i18next.language, i18next.languages, and actual loaded resources after calling changeLanguage(). [1]
  • If you’re upgrading within v25 as well: v25.4.0 adds an optional selector API for TypeScript IDE performance (enableSelector: true / "optimize"), plus related tooling. This is opt-in (not a required breaking change), but it’s included in the v25 migration guide. [1]

Primary reference: i18next Migration Guide (section “v24.x.x to v25.0.0”). [1]


🏁 Script executed:

# Search for changeLanguage calls in the codebase
rg "changeLanguage" --type ts --type tsx --type js --type jsx -A 2 -B 2

Repository: chairemobilite/evolution

Length of output: 95


🏁 Script executed:

# Search for i18next imports and usage patterns
rg "i18next|useTranslation|withTranslation" --type ts --type tsx --type js --type jsx | head -50

Repository: chairemobilite/evolution

Length of output: 95


🏁 Script executed:

# Search for changeLanguage calls in the codebase
rg "changeLanguage" -A 2 -B 2

Repository: chairemobilite/evolution

Length of output: 3180


🏁 Script executed:

# Search for i18next imports and usage patterns
rg "i18next|useTranslation|withTranslation" | head -80

Repository: chairemobilite/evolution

Length of output: 9303


Complete migration from withTranslation HOC to useTranslation hook.

Three components still use the older withTranslation pattern:

  • packages/evolution-interviewer/src/client/components/monitoring/RefreshInterviewerCache.tsx
  • packages/evolution-frontend/src/components/admin/pages/ExportInterviewData.tsx
  • packages/evolution-frontend/src/components/admin/pages/InterviewsPage.tsx

Update these to use the useTranslation hook for consistency with the rest of the codebase and modern React patterns.

🤖 Prompt for AI Agents
In `@packages/evolution-generator/package.json` at line 31, Three components
(RefreshInterviewerCache, ExportInterviewData, InterviewsPage) still use the
withTranslation HOC; convert each to the useTranslation hook: remove the import
and use of withTranslation and any WithTranslation prop types, add import {
useTranslation } from 'react-i18next', call const { t } = useTranslation() at
the top of the component body (or const { t } = useTranslation('yourNamespace')
if a namespace was used before), replace all occurrences of props.t or
this.props.t with t, and change the export to the plain component (no HOC wrap).
Ensure prop interfaces are updated to drop WithTranslation and the components
remain function components or are converted from wrapped declarations
accordingly.

The select input in map find place and the checkbox in the input range
do not need to use evolution's version of the widget. Especially that
the widget config was limited to the strict minimum because it does not
require the interview, path, etc. Stricter typescript fails to compile
with those widgets.
The `InterviewList` needs the `Filter` type, which is defined in its
parent component, so it is of unknow type. This causes compilation
failure with the react updates. Also update the component to use
the `useTranslation` hook instead of `withTranslation` HOC.
* i18next: 24.0.5 => 25.7.4
* date-fns: 2.29.1 => 4.1.0
* i18next-browser-languagedetector: 8.0.0 => 8.2.0
* react: 19.0.0 => 19.2.3
* react-datepicker: 7.6.0 => 9.1.0
* react-dom: 19.0.0 => 19.2.3
* react-i18next: 12.3.1 => 16.5.3
* react-markdown: 9.0.1 => 10.1.0
* react-router: 7.5.2 => 7.12.0
* react-select: 5.8.3 => 5.10.2
* react-spinners: 0.14.1 => 0.17.0
* remark-gfm: 4.0.0 => 4.0.1
* @testing-library/jest-dom: 6.6.3 => 6.9.1
* @testing-library/react: 16.3.0 => 16.3.1
* @types/reactj-dom: 19.0.2 => 19.2.3
* drop @types/react-select
* i18next-fs-backend:2.6.0 => 2.6.1

The `Markdown` component does not take a `className` anymore, so the
class needs to be added manually to a parent `div`. Update snapshots
accordingly.

The update the chaire-lib's bcrypt package changed the format of
password hash, so the `participantAuthModel.test.ts` needed updating.

Also, with the @testing-library/react update, it seems that the typing
in tests is now more enforced, requiring better test data.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/evolution-frontend/src/components/inputs/__tests__/InputMapFindPlace.test.tsx (1)

184-190: Test expectations correctly updated for the new InputSelect.

The comment on line 184 mentions "4 children" but the assertion now expects 3. Consider updating the comment to match.

📝 Suggested comment fix
-        // The select list should display 4 children (2 places and the 2 extra elements) and should not have a confirm button
+        // The select list should display 3 children (2 places + 1 empty option) and should not have a confirm button
🤖 Fix all issues with AI agents
In `@packages/evolution-frontend/package.json`:
- Around line 45-95: The project is missing eslint-plugin-react-hooks which
enforces the Rules of Hooks for React 19; add "eslint-plugin-react-hooks" to the
devDependencies in packages/evolution-frontend/package.json (and root
package.json if present) and then update the ESLint config
(configs/react.eslintrc.json) to extend "plugin:react-hooks/recommended" so the
rules are applied; ensure the package name is correct and run npm/yarn install
and lint to verify no new violations.

Comment on lines +45 to 95
"date-fns": "^4.1.0",
"dompurify": "^3.2.4",
"evolution-common": "^0.5.0",
"geojson": "^0.5.0",
"geojson-validation": "^1.0.2",
"gl-matrix": "^3.4.3",
"highcharts": "^12.1.2",
"highcharts-react-official": "^3.2.1",
"i18next": "^24.0.5",
"i18next-browser-languagedetector": "^8.0.0",
"i18next": "^25.7.4",
"i18next-browser-languagedetector": "^8.2.0",
"lodash": "^4.17.21",
"maplibre-gl": "^5.7.1",
"moment": "^2.30.1",
"node-fetch": "^2.6.7",
"p-queue": "^6.6.2",
"react": "^19.0.0",
"react-datepicker": "^7.6.0",
"react-dom": "^19.0.0",
"react-i18next": "^12.3.1",
"react": "^19.2.3",
"react-datepicker": "^9.1.0",
"react-dom": "^19.2.3",
"react-i18next": "^16.5.3",
"react-input-range": "^1.3.0",
"react-map-gl": "^8.0.4",
"react-markdown": "^9.0.1",
"react-markdown": "^10.1.0",
"react-modal": "^3.16.3",
"react-redux": "^9.2.0",
"react-router": "^7.5.2",
"react-select": "^5.8.3",
"react-spinners": "^0.14.1",
"react-router": "^7.12.0",
"react-select": "^5.10.2",
"react-spinners": "^0.17.0",
"react-table": "^7.8.0",
"redux": "^5.0.1",
"redux-thunk": "^3.1.0",
"remark-gfm": "^4.0.0"
"remark-gfm": "^4.0.1"
},
"devDependencies": {
"@playwright/test": "^1.56.1",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.1",
"@testing-library/user-event": "^14.6.1",
"@types/geojson": "^7946.0.16",
"@types/jest": "^30.0.0",
"@types/jest-axe": "^3.5.5",
"@types/lodash": "^4.17.21",
"@types/node": "^24.10.4",
"@types/react-dom": "^19.0.2",
"@types/react-select": "^5.0.1",
"@types/react-dom": "^19.2.3",
"@typescript-eslint/eslint-plugin": "^8.50.0",
"@typescript-eslint/parser": "^8.50.0",
"cross-env": "^10.1.0",
"eslint": "^8.57.1",
"eslint-plugin-n": "^15.7.0",
"eslint-plugin-react": "^7.37.2",
"i18next-fs-backend": "^2.6.0",
"i18next-fs-backend": "^2.6.1",
"jest": "^30.2.0",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for eslint-plugin-react-hooks in package.json files
echo "=== Searching for eslint-plugin-react-hooks ==="
rg -n "eslint-plugin-react-hooks" --type json

Repository: chairemobilite/evolution

Length of output: 115


🏁 Script executed:

#!/bin/bash
# List the actual package.json in the frontend directory
echo "=== Content of packages/evolution-frontend/package.json (devDependencies section) ==="
sed -n '/devDependencies/,/^[[:space:]]*}/p' packages/evolution-frontend/package.json | head -50

Repository: chairemobilite/evolution

Length of output: 1057


🏁 Script executed:

#!/bin/bash
# Check for test files that might cover date-fns or react-datepicker
echo "=== Searching for test files related to date-fns or react-datepicker ==="
find packages/evolution-frontend -type f \( -name "*.test.ts*" -o -name "*.test.js*" -o -name "*.spec.ts*" -o -name "*.spec.js*" \) | head -20

Repository: chairemobilite/evolution

Length of output: 1834


🏁 Script executed:

#!/bin/bash
# Check for React hooks usage and dependencies
echo "=== Checking for React compatibility references ==="
rg "eslint-plugin-react" packages/evolution-frontend/package.json -A 2 -B 2

Repository: chairemobilite/evolution

Length of output: 275


🏁 Script executed:

#!/bin/bash
# Check for eslint config files
echo "=== Looking for ESLint configuration files ==="
find packages/evolution-frontend -maxdepth 3 -type f \( -name ".eslintrc*" -o -name "eslint.config.*" \) | head -10

Repository: chairemobilite/evolution

Length of output: 157


🏁 Script executed:

#!/bin/bash
# Check if eslint-plugin-react-hooks is mentioned in any config or docs
echo "=== Searching for react-hooks references in config/docs ==="
rg "react-hooks" packages/evolution-frontend --type-list | head -20

Repository: chairemobilite/evolution

Length of output: 534


🏁 Script executed:

#!/bin/bash
# Check the root package.json for eslint-plugin-react-hooks
echo "=== Checking root package.json ==="
cat package.json | grep -A 5 -B 5 "eslint-plugin-react-hooks" 2>/dev/null || echo "Not found in root package.json"

Repository: chairemobilite/evolution

Length of output: 133


🏁 Script executed:

#!/bin/bash
# View the ESLint configuration
echo "=== Content of .eslintrc.json ==="
cat packages/evolution-frontend/.eslintrc.json

Repository: chairemobilite/evolution

Length of output: 158


🏁 Script executed:

#!/bin/bash
# Also check if there's a root eslintrc
echo "=== Checking for root .eslintrc ==="
find . -maxdepth 2 -name ".eslintrc*" -type f

Repository: chairemobilite/evolution

Length of output: 103


🏁 Script executed:

#!/bin/bash
# View the shared ESLint config
echo "=== Content of configs/react.eslintrc.json ==="
cat configs/react.eslintrc.json

Repository: chairemobilite/evolution

Length of output: 1402


Add eslint-plugin-react-hooks for React 19 compatibility.
React 19.2.x requires Rules of Hooks enforcement. The project is missing eslint-plugin-react-hooks entirely—neither the root nor frontend package.json includes it. Add it as a devDependency and extend the ESLint configuration in configs/react.eslintrc.json to include plugin:react-hooks/recommended.
Date-fns v4 and react-datepicker v9 updates appear covered by existing tests (e.g., InputDatePicker.test.tsx).

🤖 Prompt for AI Agents
In `@packages/evolution-frontend/package.json` around lines 45 - 95, The project
is missing eslint-plugin-react-hooks which enforces the Rules of Hooks for React
19; add "eslint-plugin-react-hooks" to the devDependencies in
packages/evolution-frontend/package.json (and root package.json if present) and
then update the ESLint config (configs/react.eslintrc.json) to extend
"plugin:react-hooks/recommended" so the rules are applied; ensure the package
name is correct and run npm/yarn install and lint to verify no new violations.

@tahini tahini merged commit 18a73e3 into chairemobilite:main Jan 28, 2026
6 checks passed
@tahini tahini deleted the updateTransition branch January 28, 2026 20:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants