Commit ff311e56 authored by tom's avatar tom

refactor reCaptcha field

parent 5909d485
import { Button, chakra, Flex } from '@chakra-ui/react';
import { Alert, Button, chakra, Flex } from '@chakra-ui/react';
import React from 'react';
import type { SubmitHandler } from 'react-hook-form';
import { useForm, FormProvider } from 'react-hook-form';
......@@ -11,9 +11,9 @@ import type { ResourceName } from 'lib/api/resources';
import dayjs from 'lib/date/dayjs';
import downloadBlob from 'lib/downloadBlob';
import useToast from 'lib/hooks/useToast';
import FormFieldReCaptcha from 'ui/shared/forms/fields/FormFieldReCaptcha';
import CsvExportFormField from './CsvExportFormField';
import CsvExportFormReCaptcha from './CsvExportFormReCaptcha';
interface Props {
hash: string;
......@@ -76,6 +76,13 @@ const CsvExportForm = ({ hash, resource, filterType, filterValue, fileNameTempla
}, [ resource, hash, exportType, filterType, filterValue, fileNameTemplate, toast ]);
const disabledFeatureMessage = (
<Alert status="error">
CSV export is not available at the moment since reCaptcha is not configured for this application.
Please contact the service maintainer to make necessary changes in the service configuration.
</Alert>
);
return (
<FormProvider { ...formApi }>
<chakra.form
......@@ -85,7 +92,7 @@ const CsvExportForm = ({ hash, resource, filterType, filterValue, fileNameTempla
<Flex columnGap={ 5 } rowGap={ 3 } flexDir={{ base: 'column', lg: 'row' }} alignItems={{ base: 'flex-start', lg: 'center' }} flexWrap="wrap">
{ exportType !== 'holders' && <CsvExportFormField name="from" formApi={ formApi }/> }
{ exportType !== 'holders' && <CsvExportFormField name="to" formApi={ formApi }/> }
<CsvExportFormReCaptcha formApi={ formApi }/>
<FormFieldReCaptcha disabledFeatureMessage={ disabledFeatureMessage }/>
</Flex>
<Button
variant="solid"
......
import { Alert } from '@chakra-ui/react';
import React from 'react';
import ReCaptcha from 'react-google-recaptcha';
import type { UseFormReturn } from 'react-hook-form';
import type { FormFields } from './types';
import config from 'configs/app';
interface Props {
formApi: UseFormReturn<FormFields>;
}
const CsvExportFormReCaptcha = ({ formApi }: Props) => {
const ref = React.useRef<ReCaptcha>(null);
React.useEffect(() => {
formApi.register('reCaptcha', { required: true, shouldUnregister: true });
return () => {
formApi.unregister('reCaptcha');
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
React.useEffect(() => {
ref.current?.reset();
formApi.trigger('reCaptcha');
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ formApi.formState.submitCount ]);
const handleReCaptchaChange = React.useCallback((token: string | null) => {
if (token) {
formApi.clearErrors('reCaptcha');
formApi.setValue('reCaptcha', token, { shouldValidate: true });
}
}, [ formApi ]);
const handleReCaptchaExpire = React.useCallback(() => {
formApi.resetField('reCaptcha');
formApi.setError('reCaptcha', { type: 'required' });
}, [ formApi ]);
const feature = config.features.csvExport;
if (!feature.isEnabled) {
return (
<Alert status="error">
CSV export is not available at the moment since reCaptcha is not configured for this application.
Please contact the service maintainer to make necessary changes in the service configuration.
</Alert>
);
}
return (
<ReCaptcha
className="recaptcha"
ref={ ref }
sitekey={ feature.reCaptcha.siteKey }
onChange={ handleReCaptchaChange }
onExpired={ handleReCaptchaExpire }
/>
);
};
export default CsvExportFormReCaptcha;
......@@ -8,13 +8,13 @@ import type { PublicTagTypesResponse } from 'types/api/addressMetadata';
import delay from 'lib/delay';
import useIsMobile from 'lib/hooks/useIsMobile';
import FormFieldReCaptcha from 'ui/shared/forms/fields/FormFieldReCaptcha';
import Hint from 'ui/shared/Hint';
import PublicTagsSubmitFieldAddresses from './fields/PublicTagsSubmitFieldAddresses';
import PublicTagsSubmitFieldCompanyName from './fields/PublicTagsSubmitFieldCompanyName';
import PublicTagsSubmitFieldCompanyWebsite from './fields/PublicTagsSubmitFieldCompanyWebsite';
import PublicTagsSubmitFieldDescription from './fields/PublicTagsSubmitFieldDescription';
import PublicTagsSubmitFieldReCaptcha from './fields/PublicTagsSubmitFieldReCaptcha';
import PublicTagsSubmitFieldRequesterEmail from './fields/PublicTagsSubmitFieldRequesterEmail';
import PublicTagsSubmitFieldRequesterName from './fields/PublicTagsSubmitFieldRequesterName';
import PublicTagsSubmitFieldTags from './fields/PublicTagsSubmitFieldTags';
......@@ -73,7 +73,7 @@ const PublicTagsSubmitForm = ({ config }: Props) => {
</GridItem>
<GridItem colSpan={{ base: 1, lg: 3 }}>
<PublicTagsSubmitFieldReCaptcha formApi={ formApi }/>
<FormFieldReCaptcha/>
</GridItem>
<Button
......
import React from 'react';
import ReCaptcha from 'react-google-recaptcha';
import type { UseFormReturn } from 'react-hook-form';
import type { FormFields } from '../types';
import { useFormContext } from 'react-hook-form';
import config from 'configs/app';
interface Props {
formApi: UseFormReturn<FormFields>;
disabledFeatureMessage?: JSX.Element;
}
const PublicTagsSubmitFieldReCaptcha = ({ formApi }: Props) => {
const FormFieldReCaptcha = ({ disabledFeatureMessage }: Props) => {
const { register, unregister, trigger, clearErrors, setValue, resetField, setError, formState } = useFormContext();
const ref = React.useRef<ReCaptcha>(null);
React.useEffect(() => {
formApi.register('reCaptcha', { required: true, shouldUnregister: true });
register('reCaptcha', { required: true, shouldUnregister: true });
return () => {
formApi.unregister('reCaptcha');
unregister('reCaptcha');
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
React.useEffect(() => {
ref.current?.reset();
formApi.trigger('reCaptcha');
trigger('reCaptcha');
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ formApi.formState.submitCount ]);
}, [ formState.submitCount ]);
const handleReCaptchaChange = React.useCallback((token: string | null) => {
if (token) {
formApi.clearErrors('reCaptcha');
formApi.setValue('reCaptcha', token, { shouldValidate: true });
clearErrors('reCaptcha');
setValue('reCaptcha', token, { shouldValidate: true });
}
}, [ formApi ]);
}, [ clearErrors, setValue ]);
const handleReCaptchaExpire = React.useCallback(() => {
formApi.resetField('reCaptcha');
formApi.setError('reCaptcha', { type: 'required' });
}, [ formApi ]);
const feature = config.features.csvExport;
resetField('reCaptcha');
setError('reCaptcha', { type: 'required' });
}, [ resetField, setError ]);
if (!feature.isEnabled) {
return null;
if (!config.services.reCaptcha.siteKey) {
return disabledFeatureMessage ?? null;
}
return (
<ReCaptcha
className="recaptcha"
ref={ ref }
sitekey={ feature.reCaptcha.siteKey }
sitekey={ config.services.reCaptcha.siteKey }
onChange={ handleReCaptchaChange }
onExpired={ handleReCaptchaExpire }
/>
);
};
export default PublicTagsSubmitFieldReCaptcha;
export default FormFieldReCaptcha;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment