PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.17.0
GiveWP – Donation Plugin and Fundraising Platform v4.17.0
4.17.0 4.16.9 4.16.8.1 4.16.8 4.16.7.2 4.16.7.1 4.16.7 4.16.6.1 4.16.6 4.16.5.1 4.16.5 4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 All 256 releases
give / src / DonationForms / resources / app / hooks / useVisibilityCondition.ts

useVisibilityCondition.ts in GiveWP – Donation Plugin and Fundraising Platform 4.17.0, at src/DonationForms/resources/app/hooks/useVisibilityCondition.ts

86 lines 2.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import {useMemo} from 'react';
2 import {useFormContext} from 'react-hook-form';
3 import {FieldCondition} from '@givewp/forms/types';
4 import conditionOperatorFunctions from '@givewp/forms/app/utilities/conditionOperatorFunctions';
5
6 type WatchedFields = Map<string, any>;
7
8 /**
9 * Adds visibility conditions to a field. The given conditions are watched and the hook returns true or false based on
10 * whether the conditions are met.
11 *
12 * 4.14.1 use watch instead of useWatch to get the field values.
13 * @since 3.0.0
14 */
15 export default function useVisibilityCondition(conditions: FieldCondition[]): boolean {
16 const {watch} = useFormContext();
17
18 const watchedFieldNames = useMemo<string[]>(() => {
19 if (!conditions.length) {
20 return [];
21 }
22
23 return [...conditions.reduce(watchFieldsReducer, new Set()).values()];
24 }, [conditions]);
25
26 const fieldValues = watch(watchedFieldNames);
27
28 // watch returns a numeric array of values, so we need to map them to the field names.
29 const watchedFields = useMemo<WatchedFields>(() => {
30 return watchedFieldNames.reduce((fields, name, index) => {
31 fields.set(name, fieldValues[index]);
32 return fields;
33 }, new Map());
34 }, [watchedFieldNames, fieldValues]);
35
36 return useMemo<boolean>(() => {
37 if (!conditions.length) {
38 return true;
39 }
40
41 return visibliityConditionsPass(conditions, watchedFields);
42 }, [watchedFields]);
43 }
44
45 /**
46 * Returns true or false based on whether the conditions are met.
47 *
48 * @since 3.0.0
49 */
50 export function visibliityConditionsPass(conditions: FieldCondition[], watchedFields: WatchedFields): boolean {
51 if (!conditions.length) {
52 return true;
53 }
54
55 function conditionPassReducer(passing: boolean, condition: FieldCondition) {
56 if (condition.type === 'basic') {
57 const value = watchedFields.get(condition.field);
58
59 const conditionPasses = conditionOperatorFunctions[condition.comparisonOperator](value, condition.value);
60
61 return condition.logicalOperator === 'and'
62 ? (passing ?? true) && conditionPasses
63 : (passing ?? false) || conditionPasses;
64 }
65
66 return condition.boolean === 'and'
67 ? (passing ?? true) && condition.conditions.reduce(conditionPassReducer, null)
68 : (passing ?? false) || condition.conditions.reduce(conditionPassReducer, null);
69 }
70
71 return conditions.reduce(conditionPassReducer, null);
72 }
73
74 /**
75 * A recursive reducer that returns a set of fields that are being watched by the conditions.
76 *
77 * @since 3.0.0
78 */
79 function watchFieldsReducer(fields: Set<string>, condition: FieldCondition) {
80 if (condition.type === 'basic') {
81 return fields.add(condition.field);
82 }
83
84 return condition.conditions.reduce(watchFieldsReducer, fields);
85 }
86