Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 49456 #21

Merged
merged 1 commit into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 8 additions & 33 deletions src/components/Form/FormProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import {useFocusEffect} from '@react-navigation/native';
import lodashIsEqual from 'lodash/isEqual';
import type {ForwardedRef, MutableRefObject, ReactNode, RefAttributes} from 'react';

Check failure on line 3 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'RefAttributes' is defined but never used

Check failure on line 3 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

'RefAttributes' is defined but never used
import React, {createRef, forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react';
import type {NativeSyntheticEvent, StyleProp, TextInputSubmitEditingEventData, ViewStyle} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import useLocalize from '@hooks/useLocalize';
import * as ValidationUtils from '@libs/ValidationUtils';
import Visibility from '@libs/Visibility';
Expand All @@ -13,7 +12,6 @@
import type {OnyxFormKey} from '@src/ONYXKEYS';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Form} from '@src/types/form';
import type {Network} from '@src/types/onyx';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type {RegisterInput} from './FormContext';
import FormContext from './FormContext';
Expand Down Expand Up @@ -41,30 +39,19 @@
}
}

type FormProviderOnyxProps = {
/** Contains the form state that must be accessed outside the component */
formState: OnyxEntry<Form>;

/** Contains draft values for each input in the form */
draftValues: OnyxEntry<Form>;

/** Information about the network */
network: OnyxEntry<Network>;
};

type FormProviderProps<TFormID extends OnyxFormKey = OnyxFormKey> = FormProviderOnyxProps &
type FormProviderProps<TFormID extends OnyxFormKey = OnyxFormKey> =

Check failure on line 42 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Delete `⏎····`

Check failure on line 42 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Delete `⏎····`
FormProps<TFormID> & {
/** Children to render. */

Check failure on line 44 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Replace `········` with `····`

Check failure on line 44 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Replace `········` with `····`
children: ((props: {inputValues: FormOnyxValues<TFormID>}) => ReactNode) | ReactNode;

Check failure on line 45 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Replace `········` with `····`

Check failure on line 45 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Replace `········` with `····`

/** Callback to validate the form */

Check failure on line 47 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Delete `····`

Check failure on line 47 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Delete `····`
validate?: (values: FormOnyxValues<TFormID>) => FormInputErrors<TFormID>;

Check failure on line 48 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Delete `····`

Check failure on line 48 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Delete `····`

/** Should validate function be called when input loose focus */

Check failure on line 50 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Delete `····`

Check failure on line 50 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Delete `····`
shouldValidateOnBlur?: boolean;

Check failure on line 51 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Delete `····`

Check failure on line 51 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Delete `····`

/** Should validate function be called when the value of the input is changed */

Check failure on line 53 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Replace `········` with `····`

Check failure on line 53 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Replace `········` with `····`
shouldValidateOnChange?: boolean;

Check failure on line 54 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Delete `····`

Check failure on line 54 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Delete `····`

/** Whether to remove invisible characters from strings before validation and submission */
shouldTrimValues?: boolean;
Expand All @@ -86,16 +73,17 @@
shouldValidateOnBlur = true,
shouldValidateOnChange = true,
children,
formState,
network,
enabledWhenOffline = false,
draftValues,
onSubmit,
shouldTrimValues = true,
...rest
}: FormProviderProps,
forwardedRef: ForwardedRef<FormRef>,
) {

const [network] = useOnyx(ONYXKEYS.NETWORK);
const [formState] = useOnyx(formID);
const [draftValues] = useOnyx(`${formID}Draft`);
const {preferredLocale, translate} = useLocalize();
const inputRefs = useRef<InputRefs>({});
const touchedInputs = useRef<Record<string, boolean>>({});
Expand All @@ -105,7 +93,7 @@

const onValidate = useCallback(
(values: FormOnyxValues, shouldClearServerError = true) => {
const trimmedStringValues = shouldTrimValues ? ValidationUtils.prepareValues(values) : values;

Check failure on line 96 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / typecheck

Argument of type 'Errors | (string & Errors) | null | undefined' is not assignable to parameter of type '(string & Errors) | EmptyValue'.

if (shouldClearServerError) {
FormActions.clearErrors(formID);
Expand Down Expand Up @@ -250,7 +238,7 @@
}));

const registerInput = useCallback<RegisterInput>(
(inputID, shouldSubmitForm, inputProps) => {
(inputID , shouldSubmitForm, inputProps) => {
const newRef: MutableRefObject<InputComponentBaseProps> = inputRefs.current[inputID] ?? inputProps.ref ?? createRef();
if (inputRefs.current[inputID] !== newRef) {
inputRefs.current[inputID] = newRef;
Expand All @@ -264,8 +252,8 @@
// We force the form to set the input value from the defaultValue props if there is a saved valid value
inputValues[inputID] = inputProps.defaultValue;
} else if (inputValues[inputID] === undefined) {
// We want to initialize the input value if it's undefined

Check failure on line 255 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / typecheck

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'AdditionalDetailStepForm | PersonalBankAccountForm | ReimbursementAccountForm | IssueNewExpensifyCardForm | ... 81 more ... | DebugReportActionForm'.
inputValues[inputID] = inputProps.defaultValue ?? getInitialValueByType(inputProps.valueType);

Check failure on line 256 in src/components/Form/FormProvider.tsx

View workflow job for this annotation

GitHub Actions / typecheck

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'AdditionalDetailStepForm | PersonalBankAccountForm | ReimbursementAccountForm | IssueNewExpensifyCardForm | ... 81 more ... | DebugReportActionForm'.
}

const errorFields = formState?.errorFields?.[inputID] ?? {};
Expand Down Expand Up @@ -398,19 +386,6 @@

FormProvider.displayName = 'Form';

export default withOnyx<FormProviderProps, FormProviderOnyxProps>({
network: {
key: ONYXKEYS.NETWORK,
},
// withOnyx typings are not able to handle such generic cases like this one, since it's a generic component we need to cast the keys to any
formState: {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any
key: ({formID}) => formID as any,
},
draftValues: {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any
key: (props) => `${props.formID}Draft` as any,
},
})(forwardRef(FormProvider)) as <TFormID extends OnyxFormKey>(props: Omit<FormProviderProps<TFormID> & RefAttributes<FormRef>, keyof FormProviderOnyxProps>) => ReactNode;
export default forwardRef(FormProvider) as <TFormID extends OnyxFormKey>(props: FormProviderProps<TFormID>) => ReactNode;

export type {FormProviderProps};
22 changes: 5 additions & 17 deletions src/components/Form/FormWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
// eslint-disable-next-line no-restricted-imports
import type {ScrollView as RNScrollView, StyleProp, View, ViewStyle} from 'react-native';
import {Keyboard} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
import FormElement from '@components/FormElement';
import SafeAreaConsumer from '@components/SafeAreaConsumer';
Expand All @@ -13,18 +12,11 @@
import ScrollViewWithContext from '@components/ScrollViewWithContext';
import useThemeStyles from '@hooks/useThemeStyles';
import * as ErrorUtils from '@libs/ErrorUtils';
import type {Form} from '@src/types/form';
import type ChildrenProps from '@src/types/utils/ChildrenProps';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type {FormInputErrors, FormProps, InputRefs} from './types';

type FormWrapperOnyxProps = {
/** Contains the form state that must be accessed outside the component */
formState: OnyxEntry<Form>;
};

type FormWrapperProps = ChildrenProps &
FormWrapperOnyxProps &
FormProps & {
/** Submit button styles */
submitButtonStyles?: StyleProp<ViewStyle>;
Expand All @@ -48,7 +40,6 @@
function FormWrapper({
onSubmit,
children,
formState,
errors,
inputRefs,
submitButtonText,
Expand All @@ -69,6 +60,9 @@
const styles = useThemeStyles();
const formRef = useRef<RNScrollView>(null);
const formContentRef = useRef<View>(null);

const [formState] = useOnyx(`${formID}`);

const errorMessage = useMemo(() => (formState ? ErrorUtils.getLatestErrorMessage(formState) : undefined), [formState]);

const onFixTheErrorsLinkPressed = useCallback(() => {
Expand Down Expand Up @@ -114,9 +108,9 @@
<FormAlertWithSubmitButton
buttonText={submitButtonText}
isDisabled={isSubmitDisabled}
isAlertVisible={((!isEmptyObject(errors) || !isEmptyObject(formState?.errorFields)) && !shouldHideFixErrorsAlert) || !!errorMessage}

Check failure on line 111 in src/components/Form/FormWrapper.tsx

View workflow job for this annotation

GitHub Actions / typecheck

Argument of type 'ErrorFields | (string & ErrorFields) | null | undefined' is not assignable to parameter of type '(string & ErrorFields) | EmptyValue'.
isLoading={!!formState?.isLoading}
message={isEmptyObject(formState?.errorFields) ? errorMessage : undefined}

Check failure on line 113 in src/components/Form/FormWrapper.tsx

View workflow job for this annotation

GitHub Actions / typecheck

Argument of type 'ErrorFields | (string & ErrorFields) | null | undefined' is not assignable to parameter of type '(string & ErrorFields) | EmptyValue'.
onSubmit={onSubmit}
footerContent={footerContent}
onFixTheErrorsLinkPressed={onFixTheErrorsLinkPressed}
Expand Down Expand Up @@ -189,10 +183,4 @@

FormWrapper.displayName = 'FormWrapper';

export default withOnyx<FormWrapperProps, FormWrapperOnyxProps>({
formState: {
// withOnyx typings are not able to handle such generic cases like this one, since it's a generic component we need to cast the keys to any
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any
key: (props) => props.formID as any,
},
})(FormWrapper);
export default FormWrapper;
Loading