Skip to content

Commit 19c7ff5

Browse files
Fix(v0): Handle computed presentational attributes correctly (#195)
* fix(v0): handle computed presentational attributes correctly * chore: add test for computed presentational attributes
1 parent f33dbd3 commit 19c7ff5

File tree

3 files changed

+91
-11
lines changed

3 files changed

+91
-11
lines changed

src/jsonLogic.js

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -233,12 +233,22 @@ function replaceHandlebarsTemplates({
233233
export function calculateComputedAttributes(fieldParams, { parentID = 'root' } = {}) {
234234
return ({ logic, isRequired, config, formValues }) => {
235235
const { name, computedAttributes } = fieldParams;
236-
const attributes = Object.fromEntries(
236+
let attributes = Object.fromEntries(
237237
Object.entries(computedAttributes)
238238
.map(handleComputedAttribute(logic, formValues, parentID, name))
239239
.filter(([, value]) => value !== null)
240240
);
241241

242+
const { 'x-jsf-presentation': presentation, ...rest } = attributes;
243+
244+
// Computed presentation attributes should be spread over the original attributes
245+
if (presentation) {
246+
attributes = {
247+
...rest,
248+
...presentation,
249+
};
250+
}
251+
242252
return {
243253
...attributes,
244254
schema: buildYupSchema(
@@ -274,16 +284,25 @@ function handleComputedAttribute(logic, formValues, parentID, name) {
274284
handleNestedObjectForComputedValues(value, formValues, parentID, logic, name),
275285
];
276286
case 'x-jsf-presentation': {
277-
if (value.statement) {
278-
return [
279-
'statement',
280-
handleNestedObjectForComputedValues(value.statement, formValues, parentID, logic, name),
281-
];
282-
}
283-
return [
284-
key,
285-
handleNestedObjectForComputedValues(value.statement, formValues, parentID, logic, name),
286-
];
287+
const values = {};
288+
289+
Object.entries(value).forEach(([presentationKey, presentationValue]) => {
290+
if (typeof presentationValue === 'object') {
291+
values[presentationKey] = handleNestedObjectForComputedValues(
292+
presentationValue,
293+
formValues,
294+
parentID,
295+
logic,
296+
name
297+
);
298+
} else {
299+
values[presentationKey] = logic
300+
.getScope(parentID)
301+
.applyComputedValueInField(presentationValue, formValues, name);
302+
}
303+
});
304+
305+
return [key, values];
287306
}
288307
case 'const':
289308
default: {

src/tests/jsonLogic.fixtures.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,55 @@ export const schemaWithComputedAttributesAndErrorMessages = {
364364
},
365365
};
366366

367+
export const schemaWithComputedPresentationAttributes = {
368+
properties: {
369+
amount: {
370+
description: 'Total amount to be reimbursed, including taxes.',
371+
minimum: 0,
372+
title: 'Total amount',
373+
type: 'number',
374+
'x-jsf-logic-computedAttrs': {
375+
'x-jsf-presentation': {
376+
currency: 'currency_selected',
377+
},
378+
},
379+
'x-jsf-presentation': {
380+
currency: '---',
381+
inputType: 'money',
382+
},
383+
},
384+
currency: {
385+
default: 'USD',
386+
description: 'Currency in which the expense was paid.',
387+
oneOf: [
388+
{
389+
const: 'UGX',
390+
title: 'UGX - Ugandan Shilling',
391+
},
392+
{
393+
const: 'USD',
394+
title: 'USD - United States Dollar',
395+
},
396+
],
397+
title: 'Currency',
398+
type: 'string',
399+
'x-jsf-presentation': {
400+
inputType: 'select',
401+
},
402+
},
403+
},
404+
type: 'object',
405+
'x-jsf-logic': {
406+
computedValues: {
407+
currency_selected: {
408+
rule: {
409+
var: 'currency',
410+
},
411+
},
412+
},
413+
},
414+
};
415+
367416
export const schemaWithDeepVarThatDoesNotExist = {
368417
properties: {
369418
field_a: {

src/tests/jsonLogic.test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
schemaWithValidationThatDoesNotExistOnProperty,
3636
badSchemaThatWillNotSetAForcedValue,
3737
schemaWithReduceAccumulator,
38+
schemaWithComputedPresentationAttributes,
3839
} from './jsonLogic.fixtures';
3940
import { mockConsole, restoreConsoleAndEnsureItWasNotCalled } from './testUtils';
4041
import { createHeadlessForm } from '@/createHeadlessForm';
@@ -385,6 +386,17 @@ describe('jsonLogic: cross-values validations', () => {
385386
expect(fieldB.statement).toEqual({ description: 'Must be bigger than 4 and smaller than 8' });
386387
});
387388

389+
it('presentation attributes work', () => {
390+
const { fields, handleValidation } = createHeadlessForm(
391+
schemaWithComputedPresentationAttributes,
392+
{ strictInputType: false }
393+
);
394+
const fieldB = fields.find((i) => i.name === 'amount');
395+
expect(handleValidation({ currency: 'UGX' }).formErrors).toEqual(undefined);
396+
expect(fieldB.inputType).toEqual('money');
397+
expect(fieldB.currency).toEqual('UGX');
398+
});
399+
388400
it('Use a inline-rule in a schema for a title attribute', () => {
389401
const { fields, handleValidation } = createHeadlessForm(
390402
schemaWithInlineRuleForComputedAttributeWithCopy,

0 commit comments

Comments
 (0)