diff --git a/packages/@coorpacademy-player-store/src/utils/state-extract.js b/packages/@coorpacademy-player-store/src/utils/state-extract.js index 2b0edc8471..bccdcb95ee 100644 --- a/packages/@coorpacademy-player-store/src/utils/state-extract.js +++ b/packages/@coorpacademy-player-store/src/utils/state-extract.js @@ -19,8 +19,6 @@ import { toString as _toString, isNil } from 'lodash/fp'; -// eslint-disable-next-line lodash-fp/use-fp -import {template} from 'lodash'; import type { Answer, Choice, @@ -393,14 +391,15 @@ export const getCurrentExitNode = (state: State): ExitNode | void => { const ref = progression.state.nextContent.ref; const counters = getOr({}, 'state.variables', progression); - const translateWithCounters = templateValue => - templateValue - ? // eslint-disable-next-line lodash-fp/no-extraneous-args - template(templateValue, { - interpolate: /{{([\s\S]+?)}}/g, - imports: {} - })(counters) - : null; + // Use simple string replacement instead of lodash template + // to avoid SyntaxError when content contains HTML (e.g.,
) + const translateWithCounters = (templateValue: ?string): ?string => { + if (!templateValue) return null; + return templateValue.replace(/{{([\s\S]+?)}}/g, (match: string, key: string): string => { + const trimmedKey = key.trim(); + return counters[trimmedKey] !== undefined ? counters[trimmedKey] : match; + }); + }; return pipe( getExitNode(ref), diff --git a/packages/@coorpacademy-player-store/src/utils/test/state-extract.js b/packages/@coorpacademy-player-store/src/utils/test/state-extract.js index 6f773f761c..f66aa7c026 100644 --- a/packages/@coorpacademy-player-store/src/utils/test/state-extract.js +++ b/packages/@coorpacademy-player-store/src/utils/test/state-extract.js @@ -849,6 +849,48 @@ test('getCurrentExitNode should get current exit node from state with counters', }); }); +test('getCurrentExitNode should keep unmatched template variables', t => { + const exitNode = { + ref: 'successExitNode', + title: 'Score: {{ score }}, Unknown: {{ unknownVar }}' + }; + const progression = { + state: {nextContent: {ref: 'successExitNode'}, variables: {score: 5}} + }; + const state = pipe( + set('ui.current.progressionId', '0'), + set('data.progressions.entities', {0: progression}), + set('data.exitNodes.entities', {successExitNode: exitNode}) + )({}); + + t.deepEqual(getCurrentExitNode(state), { + ref: 'successExitNode', + title: 'Score: 5, Unknown: {{ unknownVar }}' + }); +}); + +test('getCurrentExitNode should handle HTML content without crashing', t => { + const exitNode = { + ref: 'successExitNode', + title: 'Congratulations!', + description: 'Your transcript will be updated.
Thanks for your patience.' + }; + const progression = { + state: {nextContent: {ref: 'successExitNode'}, variables: {}} + }; + const state = pipe( + set('ui.current.progressionId', '0'), + set('data.progressions.entities', {0: progression}), + set('data.exitNodes.entities', {successExitNode: exitNode}) + )({}); + + t.deepEqual(getCurrentExitNode(state), { + ref: 'successExitNode', + title: 'Congratulations!', + description: 'Your transcript will be updated.
Thanks for your patience.' + }); +}); + test('getCurrentExitNode should return undefined if no progression is found', t => { const state = set('ui.current.progressionId', '0')({}); t.is(getCurrentExitNode(state), undefined);