PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 3.9.0
GiveWP – Donation Plugin and Fundraising Platform v3.9.0
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 2.30.0 2.31.0 2.31.1 All 253 releases
give / src / DonationForms / resources / app / hooks / useVisibilityCondition.ts
useVisibilityCondition.ts
85 lines 2.7 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 {useWatch} 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 * @since 3.0.0
13 */
14 export default function useVisibilityCondition(conditions: FieldCondition[]): boolean {
15 const watchedFieldNames = useMemo<string[]>(() => {
16 if (!conditions.length) {
17 return [];
18 }
19
20 return [...conditions.reduce(watchFieldsReducer, new Set()).values()];
21 }, [conditions]);
22
23 const fieldValues = useWatch({
24 name: watchedFieldNames,
25 });
26
27 // useWatch returns a numeric array of values, so we need to map them to the field names.
28 const watchedFields = useMemo<WatchedFields>(() => {
29 return watchedFieldNames.reduce((fields, name, index) => {
30 fields.set(name, fieldValues[index]);
31 return fields;
32 }, new Map());
33 }, [watchedFieldNames, fieldValues]);
34
35 return useMemo<boolean>(() => {
36 if (!conditions.length) {
37 return true;
38 }
39
40 return visibliityConditionsPass(conditions, watchedFields);
41 }, [watchedFields]);
42 }
43
44 /**
45 * Returns true or false based on whether the conditions are met.
46 *
47 * @since 3.0.0
48 */
49 export function visibliityConditionsPass(conditions: FieldCondition[], watchedFields: WatchedFields): boolean {
50 if (!conditions.length) {
51 return true;
52 }
53
54 function conditionPassReducer(passing: boolean, condition: FieldCondition) {
55 if (condition.type === 'basic') {
56 const value = watchedFields.get(condition.field);
57
58 const conditionPasses = conditionOperatorFunctions[condition.comparisonOperator](value, condition.value);
59
60 return condition.logicalOperator === 'and'
61 ? (passing ?? true) && conditionPasses
62 : (passing ?? false) || conditionPasses;
63 }
64
65 return condition.boolean === 'and'
66 ? (passing ?? true) && condition.conditions.reduce(conditionPassReducer, null)
67 : (passing ?? false) || condition.conditions.reduce(conditionPassReducer, null);
68 }
69
70 return conditions.reduce(conditionPassReducer, null);
71 }
72
73 /**
74 * A recursive reducer that returns a set of fields that are being watched by the conditions.
75 *
76 * @since 3.0.0
77 */
78 function watchFieldsReducer(fields: Set<string>, condition: FieldCondition) {
79 if (condition.type === 'basic') {
80 return fields.add(condition.field);
81 }
82
83 return condition.conditions.reduce(watchFieldsReducer, fields);
84 }
85