Skip to content

Commit

Permalink
feat: implemented visibleOn for nested inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
chesterkmr committed Sep 28, 2024
1 parent 0783b84 commit 28d3b25
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { useDynamicUIContext } from '@/components/organisms/DynamicUI/hooks/useD
import { useRuleExecutor } from '@/components/organisms/DynamicUI/hooks/useRuleExecutor';
import { useStateManagerContext } from '@/components/organisms/DynamicUI/StateManager/components/StateProvider';
import { findDefinitionByName } from '@/components/organisms/UIRenderer/elements/JSONForm/helpers/findDefinitionByName';
import { getInputIndex } from '@/components/organisms/UIRenderer/elements/JSONForm/hocs/withDynamicUIInput';
import { useJSONFormDefinition } from '@/components/organisms/UIRenderer/elements/JSONForm/providers/JSONFormDefinitionProvider/useJSONFormDefinition';
import { useUIElementProps } from '@/components/organisms/UIRenderer/hooks/useUIElementProps';
import { UIElement } from '@/domains/collection-flow';
import { AnyObject, FieldLayout } from '@ballerine/ui';

Expand All @@ -18,14 +20,21 @@ export const FieldTemplate = (props: FieldTemplateProps) => {
const { state } = useDynamicUIContext();
const { payload } = useStateManagerContext();
const { definition } = useJSONFormDefinition();
const inputIndex = useMemo(() => {
const index = getInputIndex(props.id || '');

return isNaN(index as number) ? null : index;
}, [props.id]);

const fieldDefinition = useMemo(
() =>
findDefinitionByName(props.id.replace('root_', ''), definition.elements || []) ||
findDefinitionByName(props.id.replace(/root_\d*_?/, ''), definition.elements || []) ||
({} as UIElement<AnyObject>),
[props.id, definition.elements],
);

const { hidden } = useUIElementProps(fieldDefinition, inputIndex);

const rules = useMemo(() => fieldDefinition.requiredOn || [], [fieldDefinition.requiredOn]);

const rulesResults = useRuleExecutor(payload, rules, fieldDefinition, state);
Expand All @@ -39,6 +48,8 @@ export const FieldTemplate = (props: FieldTemplateProps) => {
[rulesResults, props.required],
);

if (hidden) return null;

return (
<div className="max-w-[385px]">
<FieldLayout {...props} required={isRequired} optionalLabel={optionalLabel} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AnyObject } from '@ballerine/ui';

export const findDefinitionByName = (
name: string,
elements: UIElement<AnyObject>[],
elements: Array<UIElement<AnyObject>>,
): UIElement<AnyObject> | undefined => {
for (const element of elements) {
if (element.name === name) {
Expand All @@ -13,6 +13,7 @@ export const findDefinitionByName = (

if (element.elements) {
const foundInChildren = findDefinitionByName(name, element.elements);

if (foundInChildren) {
return foundInChildren;
}
Expand All @@ -24,7 +25,7 @@ export const findDefinitionByName = (

export const findDefinitionByDestinationPath = (
destination: string,
elements: UIElement<AnyObject>[],
elements: Array<UIElement<AnyObject>>,
): UIElement<AnyObject> | undefined => {
for (const element of elements) {
if (element.valueDestination === destination) {
Expand All @@ -33,6 +34,7 @@ export const findDefinitionByDestinationPath = (

if (element.elements) {
const foundInChildren = findDefinitionByDestinationPath(destination, element.elements);

if (foundInChildren) {
return foundInChildren;
}
Expand All @@ -44,7 +46,7 @@ export const findDefinitionByDestinationPath = (

export const findDocumentDefinitionById = (
id: string,
elements: UIElement<AnyObject>[],
elements: Array<UIElement<AnyObject>>,
): UIElement<AnyObject> | undefined => {
for (const element of elements) {
if ((element?.options?.documentData?.id as string) === deserializeDocumentId(id)) {
Expand All @@ -53,6 +55,7 @@ export const findDocumentDefinitionById = (

if (element.elements) {
const foundInChildren = findDocumentDefinitionById(id, element.elements);

if (foundInChildren) {
return foundInChildren;
}
Expand All @@ -62,10 +65,10 @@ export const findDocumentDefinitionById = (
return undefined;
};

export const getAllDefinitions = (elements: UIElement<AnyObject>[]) => {
const items: UIElement<AnyObject>[] = [];
export const getAllDefinitions = (elements: Array<UIElement<AnyObject>>) => {
const items: Array<UIElement<AnyObject>> = [];

const run = (elements: UIElement<AnyObject>[]) => {
const run = (elements: Array<UIElement<AnyObject>>) => {
for (const element of elements) {
if (element.valueDestination) {
items.push(element);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const findLastDigit = (str: string) => {
return null;
};

const getInputIndex = (inputId: string) => findLastDigit(inputId);
export const getInputIndex = (inputId: string) => findLastDigit(inputId);

const injectIndexToDestinationIfNeeded = (destination: string, index: number | null): string => {
if (index === null) return destination;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Rule } from '@/domains/collection-flow';

export const injectIndexesAtRulesPaths = (rules: Rule[], index: number | null = null) => {
if (index === null) return rules;

if (!Array.isArray(rules)) return rules;

const result = rules.map(rule => {
if (rule.type === 'json-logic') {
const stringValue = JSON.stringify(rule.value);
const newValue = JSON.parse(
stringValue.replace(/\[({INDEX})\]/g, (match, p1, offset, string) => {
const before = string[offset - 1];
const after = string[offset + match.length];
const prefix = before && before !== '.' ? '.' : '';
const suffix = after && after !== '.' ? '.' : '';

return `${prefix}${index}${suffix}`;
}),
);

return {
...rule,
value: newValue,
};
}

return rule;
});

return result;
};
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
import { useStateManagerContext } from '@/components/organisms/DynamicUI/StateManager/components/StateProvider';
import { useDynamicUIContext } from '@/components/organisms/DynamicUI/hooks/useDynamicUIContext';
import { useRuleExecutor } from '@/components/organisms/DynamicUI/hooks/useRuleExecutor';
import { injectIndexesAtRulesPaths } from '@/components/organisms/UIRenderer/hooks/useUIElementProps/helpers';
import { useUIElementState } from '@/components/organisms/UIRenderer/hooks/useUIElementState';
import { UIElement } from '@/domains/collection-flow';
import { AnyObject } from '@ballerine/ui';
import { useMemo } from 'react';

export const useUIElementProps = (definition: UIElement<AnyObject>) => {
export const useUIElementProps = (
definition: UIElement<AnyObject>,
index: number | null = null,
) => {
const { payload } = useStateManagerContext();
const { state } = useDynamicUIContext();
const availabilityRules = useMemo(() => {
return injectIndexesAtRulesPaths(definition.availableOn || [], index);
}, [definition, index]);

const visibilityRules = useMemo(() => {
return injectIndexesAtRulesPaths(definition.visibleOn || [], index);
}, [definition, index]);

const [availabilityTestResulsts, visibilityTestResults] = [
useRuleExecutor(
payload,
// @ts-ignore
definition.availableOn,
availabilityRules,
definition,
state,
),
useRuleExecutor(
payload,
// @ts-ignore
definition.visibleOn,
visibilityRules,
definition,
state,
),
Expand Down

0 comments on commit 28d3b25

Please sign in to comment.