feat: add new commit trigger in GitHub
This commit is contained in:
101
packages/web/src/hooks/useDynamicData.ts
Normal file
101
packages/web/src/hooks/useDynamicData.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import * as React from 'react';
|
||||
import { useLazyQuery } from '@apollo/client';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import set from 'lodash/set';
|
||||
import type { UseFormReturn } from 'react-hook-form';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import type { IField, IFieldDropdown, IJSONObject } from '@automatisch/types';
|
||||
|
||||
import { GET_DATA } from 'graphql/queries/get-data';
|
||||
|
||||
const variableRegExp = /({.*?})/g;
|
||||
|
||||
function computeArguments(args: IFieldDropdown["source"]["arguments"], getValues: UseFormReturn["getValues"]): IJSONObject {
|
||||
const initialValue = {};
|
||||
return args.reduce(
|
||||
(result, { name, value }) => {
|
||||
const isVariable = variableRegExp.test(value);
|
||||
|
||||
if (isVariable) {
|
||||
const sanitizedFieldPath = value.replace(/{|}/g, '');
|
||||
const computedValue = getValues(sanitizedFieldPath);
|
||||
|
||||
if (!computedValue) throw new Error(`The ${sanitizedFieldPath} field is required.`);
|
||||
|
||||
set(result, name, computedValue);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
set(result, name, value);
|
||||
|
||||
return result;
|
||||
},
|
||||
initialValue
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Fetch the dynamic data for the given step.
|
||||
* This hook must be within a react-hook-form context.
|
||||
*
|
||||
* @param stepId - the id of the step
|
||||
* @param schema - the field that needs the dynamic data
|
||||
*/
|
||||
function useDynamicData(stepId: string | undefined, schema: IField) {
|
||||
const lastComputedVariables = React.useRef({});
|
||||
const [getData, { called, data, loading }] = useLazyQuery(GET_DATA);
|
||||
const { getValues } = useFormContext();
|
||||
const formValues = getValues();
|
||||
|
||||
/**
|
||||
* Return `null` when even a field is missing value.
|
||||
*
|
||||
* This must return the same reference if no computed variable is changed.
|
||||
* Otherwise, it causes redundant network request!
|
||||
*/
|
||||
const computedVariables = React.useMemo(() => {
|
||||
if (schema.type === 'dropdown' && schema.source) {
|
||||
try {
|
||||
const variables = computeArguments(schema.source.arguments, getValues);
|
||||
|
||||
// if computed variables are the same, return the last computed variables.
|
||||
if (isEqual(variables, lastComputedVariables.current)) {
|
||||
return lastComputedVariables.current;
|
||||
}
|
||||
|
||||
lastComputedVariables.current = variables;
|
||||
|
||||
return variables;
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
/**
|
||||
* `formValues` is to trigger recomputation when form is updated.
|
||||
* `getValues` is for convenience as it supports paths for fields like `getValues('foo.bar.baz')`.
|
||||
*/
|
||||
}, [schema, formValues, getValues]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (schema.type === 'dropdown' && stepId && schema.source && computedVariables) {
|
||||
getData({
|
||||
variables: {
|
||||
stepId,
|
||||
...computedVariables,
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [getData, stepId, schema, computedVariables]);
|
||||
|
||||
return {
|
||||
called,
|
||||
data: data?.getData,
|
||||
loading,
|
||||
};
|
||||
}
|
||||
|
||||
export default useDynamicData;
|
Reference in New Issue
Block a user