diff --git a/src/components/Tool/Appeal/AppealDetails/AppealHeaderInfo.test.tsx b/src/components/Tool/Appeal/AppealDetails/AppealHeaderInfo.test.tsx
deleted file mode 100644
index 9533e6a6a..000000000
--- a/src/components/Tool/Appeal/AppealDetails/AppealHeaderInfo.test.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import { ThemeProvider } from '@mui/material/styles';
-import { LocalizationProvider } from '@mui/x-date-pickers';
-import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon';
-import { render, waitFor } from '@testing-library/react';
-import TestRouter from '__tests__/util/TestRouter';
-import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
-import { AppealsWrapper } from 'pages/accountLists/[accountListId]/tools/appeals/AppealsWrapper';
-import theme from 'src/theme';
-import { appealInfo } from '../appealMockData';
-import { AppealHeaderInfo, AppealHeaderInfoProps } from './AppealHeaderInfo';
-
-const router = {
- query: { accountListId: 'aaa' },
- isReady: true,
-};
-
-const Components = ({ appealInfo, loading }: AppealHeaderInfoProps) => (
-
-
-
-
-
-
-
-
-
-
-
-);
-
-describe('AppealHeaderInfo', () => {
- it('renders skeletons when loading', () => {
- const { getByTestId, getByRole } = render(
- ,
- );
-
- expect(getByRole('heading', { name: 'Name:' })).toBeInTheDocument();
- expect(getByTestId('appeal-name-skeleton')).toBeInTheDocument();
-
- expect(getByRole('heading', { name: 'Goal:' })).toBeInTheDocument();
- expect(getByTestId('appeal-goal-skeleton')).toBeInTheDocument();
- });
-
- it('renders appeal info', async () => {
- const { getByText } = render(
- ,
- );
-
- await waitFor(() => {
- expect(getByText('Test Appeal')).toBeInTheDocument();
- expect(getByText('$100')).toBeInTheDocument();
- expect(getByText(/\$50 \(50%\)/i)).toBeInTheDocument();
- expect(getByText(/\$100 \(100%\)/i)).toBeInTheDocument();
- });
- });
-
- // TODO - Build tests for modals opening and saving data
-});
diff --git a/src/components/Tool/Appeal/AppealDetails/AppealHeaderInfo/AppealHeaderInfo.test.tsx b/src/components/Tool/Appeal/AppealDetails/AppealHeaderInfo/AppealHeaderInfo.test.tsx
new file mode 100644
index 000000000..f866f1d26
--- /dev/null
+++ b/src/components/Tool/Appeal/AppealDetails/AppealHeaderInfo/AppealHeaderInfo.test.tsx
@@ -0,0 +1,86 @@
+import { ThemeProvider } from '@mui/material/styles';
+import { LocalizationProvider } from '@mui/x-date-pickers';
+import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon';
+import { render, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { SnackbarProvider } from 'notistack';
+import TestRouter from '__tests__/util/TestRouter';
+import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
+import { AppealsWrapper } from 'pages/accountLists/[accountListId]/tools/appeals/AppealsWrapper';
+import theme from 'src/theme';
+import { appealInfo } from '../../appealMockData';
+import { AppealHeaderInfo, AppealHeaderInfoProps } from './AppealHeaderInfo';
+
+const router = {
+ query: { accountListId: 'aaa' },
+ isReady: true,
+};
+
+const Components = ({ appealInfo, loading }: AppealHeaderInfoProps) => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
+
+describe('AppealHeaderInfo', () => {
+ it('renders skeletons when loading', () => {
+ const { getByTestId, getByRole } = render(
+ ,
+ );
+
+ expect(getByRole('heading', { name: 'Name:' })).toBeInTheDocument();
+ expect(getByTestId('appeal-name-skeleton')).toBeInTheDocument();
+
+ expect(getByRole('heading', { name: 'Goal:' })).toBeInTheDocument();
+ expect(getByTestId('appeal-goal-skeleton')).toBeInTheDocument();
+ });
+
+ it('renders appeal info', async () => {
+ const { getByText, findByText } = render(
+ ,
+ );
+
+ expect(await findByText('Test Appeal')).toBeInTheDocument();
+
+ expect(getByText('$100')).toBeInTheDocument();
+ expect(getByText(/\$50 \(50%\)/i)).toBeInTheDocument();
+ expect(getByText(/\$100 \(100%\)/i)).toBeInTheDocument();
+ });
+
+ it('should allow user to open the edit appeal info modal', async () => {
+ const { findByText, findByRole, getByTestId, getByRole, queryByRole } =
+ render();
+
+ expect(await findByText('Test Appeal')).toBeInTheDocument();
+
+ userEvent.click(getByTestId('edit-appeal-name'));
+
+ expect(
+ await findByRole('heading', { name: 'Edit Appeal' }),
+ ).toBeInTheDocument();
+
+ userEvent.click(getByTestId('edit-appeal-goal'));
+
+ expect(
+ await findByRole('heading', { name: 'Edit Appeal' }),
+ ).toBeInTheDocument();
+
+ userEvent.click(getByRole('button', { name: 'Close' }));
+
+ await waitFor(() => {
+ expect(
+ queryByRole('heading', { name: 'Edit Appeal' }),
+ ).not.toBeInTheDocument();
+ });
+ });
+});
diff --git a/src/components/Tool/Appeal/AppealDetails/AppealHeaderInfo.tsx b/src/components/Tool/Appeal/AppealDetails/AppealHeaderInfo/AppealHeaderInfo.tsx
similarity index 95%
rename from src/components/Tool/Appeal/AppealDetails/AppealHeaderInfo.tsx
rename to src/components/Tool/Appeal/AppealDetails/AppealHeaderInfo/AppealHeaderInfo.tsx
index 07e208907..1bd1e8a99 100644
--- a/src/components/Tool/Appeal/AppealDetails/AppealHeaderInfo.tsx
+++ b/src/components/Tool/Appeal/AppealDetails/AppealHeaderInfo/AppealHeaderInfo.tsx
@@ -7,11 +7,11 @@ import { EditIcon } from 'src/components/Contacts/ContactDetails/ContactDetailsT
import { useLocale } from 'src/hooks/useLocale';
import { currencyFormat } from 'src/lib/intlFormat';
import theme from 'src/theme';
-import AppealProgressBar from '../AppealProgressBar';
import {
DynamicEditAppealHeaderInfoModal,
preloadEditAppealHeaderInfoModal,
-} from './EditAppealHeaderInfoModal/DynamicEditAppealHeaderInfoModal';
+} from '../../Modals/EditAppealHeaderInfoModal/DynamicEditAppealHeaderInfoModal';
+import AppealProgressBar from '../AppealProgressBar/AppealProgressBar';
export const appealHeaderInfoHeight = theme.spacing(9);
@@ -95,6 +95,7 @@ export const AppealHeaderInfo: React.FC = ({
onClick={() => setIsEditAppealModalOpen(true)}
onMouseOver={preloadEditAppealHeaderInfoModal}
aria-label={t('Edit Icon')}
+ data-testid="edit-appeal-name"
>
@@ -126,6 +127,7 @@ export const AppealHeaderInfo: React.FC = ({
onClick={() => setIsEditAppealModalOpen(true)}
onMouseOver={preloadEditAppealHeaderInfoModal}
aria-label={t('Edit Icon')}
+ data-testid="edit-appeal-goal"
>
diff --git a/src/components/Tool/Appeal/AppealProgressBar.test.tsx b/src/components/Tool/Appeal/AppealDetails/AppealProgressBar/AppealProgressBar.test.tsx
similarity index 100%
rename from src/components/Tool/Appeal/AppealProgressBar.test.tsx
rename to src/components/Tool/Appeal/AppealDetails/AppealProgressBar/AppealProgressBar.test.tsx
diff --git a/src/components/Tool/Appeal/AppealProgressBar.tsx b/src/components/Tool/Appeal/AppealDetails/AppealProgressBar/AppealProgressBar.tsx
similarity index 99%
rename from src/components/Tool/Appeal/AppealProgressBar.tsx
rename to src/components/Tool/Appeal/AppealDetails/AppealProgressBar/AppealProgressBar.tsx
index e26f08638..8e78b6afa 100644
--- a/src/components/Tool/Appeal/AppealProgressBar.tsx
+++ b/src/components/Tool/Appeal/AppealDetails/AppealProgressBar/AppealProgressBar.tsx
@@ -3,7 +3,7 @@ import { Box, Theme, Tooltip, Typography } from '@mui/material';
import { makeStyles } from 'tss-react/mui';
import { useLocale } from 'src/hooks/useLocale';
import { currencyFormat } from 'src/lib/intlFormat';
-import theme from '../../../theme';
+import theme from 'src/theme';
const useStyles = makeStyles()((theme: Theme) => ({
colorYellow: {
diff --git a/src/components/Tool/Appeal/Flow/ContactFlow.tsx b/src/components/Tool/Appeal/Flow/ContactFlow.tsx
index f6586c8ef..45aadbde0 100644
--- a/src/components/Tool/Appeal/Flow/ContactFlow.tsx
+++ b/src/components/Tool/Appeal/Flow/ContactFlow.tsx
@@ -11,7 +11,7 @@ import { ContactFlowDragLayer } from 'src/components/Contacts/ContactFlow/Contac
import { ContactFilterSetInput } from 'src/graphql/types.generated';
import i18n from 'src/lib/i18n';
import theme from 'src/theme';
-import { AppealHeaderInfo } from '../AppealDetails/AppealHeaderInfo';
+import { AppealHeaderInfo } from '../AppealDetails/AppealHeaderInfo/AppealHeaderInfo';
import { AppealQuery } from '../AppealDetails/AppealsMainPanel/AppealInfo.generated';
import { AppealStatusEnum } from '../AppealsContext/AppealsContext';
import { ContactFlowColumn } from './ContactFlowColumn/ContactFlowColumn';
diff --git a/src/components/Tool/Appeal/Flow/ContactFlowColumn/ContactFlowColumn.tsx b/src/components/Tool/Appeal/Flow/ContactFlowColumn/ContactFlowColumn.tsx
index 21907636c..e000a25ba 100644
--- a/src/components/Tool/Appeal/Flow/ContactFlowColumn/ContactFlowColumn.tsx
+++ b/src/components/Tool/Appeal/Flow/ContactFlowColumn/ContactFlowColumn.tsx
@@ -27,7 +27,7 @@ import {
AppealsContext,
AppealsType,
} from 'src/components/Tool/Appeal/AppealsContext/AppealsContext';
-import { appealHeaderInfoHeight } from '../../AppealDetails/AppealHeaderInfo';
+import { appealHeaderInfoHeight } from '../../AppealDetails/AppealHeaderInfo/AppealHeaderInfo';
import { ContactFlowDropZone } from '../ContactFlowDropZone/ContactFlowDropZone';
import { ContactFlowRow } from '../ContactFlowRow/ContactFlowRow';
diff --git a/src/components/Tool/Appeal/InitialPage/Appeal.tsx b/src/components/Tool/Appeal/InitialPage/Appeal.tsx
index c66b510df..23a13fb3f 100644
--- a/src/components/Tool/Appeal/InitialPage/Appeal.tsx
+++ b/src/components/Tool/Appeal/InitialPage/Appeal.tsx
@@ -9,7 +9,7 @@ import { AppealFieldsFragment } from 'pages/accountLists/[accountListId]/tools/G
import { useAccountListId } from '../../../../hooks/useAccountListId';
import theme from '../../../../theme';
import AnimatedCard from '../../../AnimatedCard';
-import AppealProgressBar from '../AppealProgressBar';
+import AppealProgressBar from '../AppealDetails/AppealProgressBar/AppealProgressBar';
const useStyles = makeStyles()(() => ({
cardContent: {
diff --git a/src/components/Tool/Appeal/List/ContactsList/ContactsList.tsx b/src/components/Tool/Appeal/List/ContactsList/ContactsList.tsx
index a8d242821..d8eb9d764 100644
--- a/src/components/Tool/Appeal/List/ContactsList/ContactsList.tsx
+++ b/src/components/Tool/Appeal/List/ContactsList/ContactsList.tsx
@@ -11,7 +11,7 @@ import theme from 'src/theme';
import {
AppealHeaderInfo,
appealHeaderInfoHeight,
-} from '../../AppealDetails/AppealHeaderInfo';
+} from '../../AppealDetails/AppealHeaderInfo/AppealHeaderInfo';
import { AppealQuery } from '../../AppealDetails/AppealsMainPanel/AppealInfo.generated';
import {
AppealStatusEnum,
diff --git a/src/components/Tool/Appeal/Modals/AddExcludedContactModal/AddExcludedContactModal.test.tsx b/src/components/Tool/Appeal/Modals/AddExcludedContactModal/AddExcludedContactModal.test.tsx
index 315581657..ebf6bc0f9 100644
--- a/src/components/Tool/Appeal/Modals/AddExcludedContactModal/AddExcludedContactModal.test.tsx
+++ b/src/components/Tool/Appeal/Modals/AddExcludedContactModal/AddExcludedContactModal.test.tsx
@@ -12,7 +12,7 @@ import { AppealsWrapper } from 'pages/accountLists/[accountListId]/tools/appeals
import i18n from 'src/lib/i18n';
import theme from 'src/theme';
import { AppealsContext } from '../../AppealsContext/AppealsContext';
-import { AppealQuery } from '../AddContactToAppealModal/appealInfo.generated';
+import { AppealQuery } from '../AddContactToAppealModal/AppealInfo.generated';
import { AddExcludedContactModal } from './AddExcludedContactModal';
const accountListId = 'abc';
diff --git a/src/components/Tool/Appeal/Modals/AddExcludedContactModal/AddExcludedContactModal.tsx b/src/components/Tool/Appeal/Modals/AddExcludedContactModal/AddExcludedContactModal.tsx
index 95f187c35..707fbd3a1 100644
--- a/src/components/Tool/Appeal/Modals/AddExcludedContactModal/AddExcludedContactModal.tsx
+++ b/src/components/Tool/Appeal/Modals/AddExcludedContactModal/AddExcludedContactModal.tsx
@@ -18,7 +18,7 @@ import {
AppealsContext,
AppealsType,
} from '../../AppealsContext/AppealsContext';
-import { useAppealQuery } from '../AddContactToAppealModal/appealInfo.generated';
+import { useAppealQuery } from '../AddContactToAppealModal/AppealInfo.generated';
import { useAssignContactsToAppealMutation } from './AddExcludedContactModal.generated';
const LoadingIndicator = styled(CircularProgress)(({ theme }) => ({
diff --git a/src/components/Tool/Appeal/Modals/EditAppealHeaderInfoModal/DynamicEditAppealHeaderInfoModal.tsx b/src/components/Tool/Appeal/Modals/EditAppealHeaderInfoModal/DynamicEditAppealHeaderInfoModal.tsx
new file mode 100644
index 000000000..e90ce122d
--- /dev/null
+++ b/src/components/Tool/Appeal/Modals/EditAppealHeaderInfoModal/DynamicEditAppealHeaderInfoModal.tsx
@@ -0,0 +1,12 @@
+import dynamic from 'next/dynamic';
+import { DynamicModalPlaceholder } from 'src/components/DynamicPlaceholders/DynamicModalPlaceholder';
+
+export const preloadEditAppealHeaderInfoModal = () =>
+ import(
+ /* webpackChunkName: "EditAppealHeaderInfoModal" */ './EditAppealHeaderInfoModal'
+ ).then(({ EditAppealHeaderInfoModal }) => EditAppealHeaderInfoModal);
+
+export const DynamicEditAppealHeaderInfoModal = dynamic(
+ preloadEditAppealHeaderInfoModal,
+ { loading: DynamicModalPlaceholder },
+);
diff --git a/src/components/Tool/Appeal/Modals/EditAppealHeaderInfoModal/EditAppeal.graphql b/src/components/Tool/Appeal/Modals/EditAppealHeaderInfoModal/EditAppeal.graphql
new file mode 100644
index 000000000..00ca6e0d7
--- /dev/null
+++ b/src/components/Tool/Appeal/Modals/EditAppealHeaderInfoModal/EditAppeal.graphql
@@ -0,0 +1,8 @@
+mutation UpdateAppeal($input: AppealUpdateMutationInput!) {
+ updateAppeal(input: $input) {
+ appeal {
+ name
+ amount
+ }
+ }
+}
diff --git a/src/components/Tool/Appeal/Modals/EditAppealHeaderInfoModal/EditAppealHeaderInfoModal.test.tsx b/src/components/Tool/Appeal/Modals/EditAppealHeaderInfoModal/EditAppealHeaderInfoModal.test.tsx
new file mode 100644
index 000000000..3eae8d143
--- /dev/null
+++ b/src/components/Tool/Appeal/Modals/EditAppealHeaderInfoModal/EditAppealHeaderInfoModal.test.tsx
@@ -0,0 +1,150 @@
+import React from 'react';
+import { ThemeProvider } from '@mui/material/styles';
+import { render, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { SnackbarProvider } from 'notistack';
+import { DndProvider } from 'react-dnd';
+import { HTML5Backend } from 'react-dnd-html5-backend';
+import TestRouter from '__tests__/util/TestRouter';
+import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
+import { AppealFieldsFragment } from 'pages/accountLists/[accountListId]/tools/GetAppeals.generated';
+import { AppealsWrapper } from 'pages/accountLists/[accountListId]/tools/appeals/AppealsWrapper';
+import theme from 'src/theme';
+import { appealInfo } from '../../appealMockData';
+import { EditAppealHeaderInfoModal } from './EditAppealHeaderInfoModal';
+
+const accountListId = 'abc';
+const router = {
+ query: { accountListId },
+ isReady: true,
+};
+const handleClose = jest.fn();
+const mutationSpy = jest.fn();
+
+const Components = ({
+ appeal = appealInfo,
+}: {
+ appeal?: AppealFieldsFragment;
+}) => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
+
+describe('EditAppealHeaderInfoModal', () => {
+ it('should show errors', () => {
+ const { getByRole, getByTestId } = render(
+ ,
+ );
+
+ userEvent.clear(getByRole('spinbutton', { name: /goal/i }));
+ userEvent.tab();
+
+ expect(getByRole('textbox', { name: /name/i })).toHaveValue('');
+ expect(getByRole('spinbutton', { name: /goal/i })).toHaveValue(null);
+
+ expect(getByTestId('nameError')).toBeInTheDocument();
+ expect(getByTestId('amountError')).toBeInTheDocument();
+ });
+
+ it('default', () => {
+ const { getByRole } = render();
+
+ expect(getByRole('textbox', { name: /name/i })).toHaveValue('Test Appeal');
+ expect(getByRole('spinbutton', { name: /goal/i })).toHaveValue(100);
+ });
+
+ it('should edit fields and save appeal', async () => {
+ const { getByRole } = render();
+
+ const name = getByRole('textbox', { name: /name/i });
+ const amount = getByRole('spinbutton', { name: /goal/i });
+
+ userEvent.clear(name);
+ userEvent.type(name, 'New Appeal Name');
+ userEvent.clear(amount);
+ userEvent.type(amount, '500');
+
+ userEvent.click(getByRole('button', { name: 'Save' }));
+
+ await waitFor(() => {
+ expect(mutationSpy).toHaveGraphqlOperation('UpdateAppeal', {
+ input: {
+ accountListId,
+ attributes: {
+ id: '1',
+ name: 'New Appeal Name',
+ amount: 500,
+ },
+ },
+ });
+ });
+ });
+
+ it('should show amount error', async () => {
+ const { getByRole, getByText, queryByText } = render();
+
+ const name = getByRole('textbox', { name: /name/i });
+ const amount = getByRole('spinbutton', { name: /goal/i });
+
+ userEvent.clear(name);
+ userEvent.type(name, 'New Appeal Name');
+ userEvent.clear(amount);
+
+ userEvent.type(amount, '100');
+ userEvent.clear(amount);
+
+ await waitFor(() =>
+ expect(getByText(/please enter a goal/i)).toBeInTheDocument(),
+ );
+
+ userEvent.clear(amount);
+ userEvent.type(amount, '-100');
+
+ await waitFor(() =>
+ expect(
+ getByText(/must use a positive number for appeal amount/i),
+ ).toBeInTheDocument(),
+ );
+ userEvent.clear(amount);
+ userEvent.type(amount, '400');
+ await waitFor(() =>
+ expect(
+ queryByText(/must use a positive number for appeal amount/i),
+ ).not.toBeInTheDocument(),
+ );
+
+ userEvent.click(getByRole('button', { name: 'Save' }));
+
+ await waitFor(() => {
+ expect(mutationSpy).toHaveGraphqlOperation('UpdateAppeal', {
+ input: {
+ accountListId,
+ attributes: {
+ id: '1',
+ name: 'New Appeal Name',
+ amount: 400,
+ },
+ },
+ });
+ });
+ });
+});
diff --git a/src/components/Tool/Appeal/Modals/EditAppealHeaderInfoModal/EditAppealHeaderInfoModal.tsx b/src/components/Tool/Appeal/Modals/EditAppealHeaderInfoModal/EditAppealHeaderInfoModal.tsx
new file mode 100644
index 000000000..fbec871b7
--- /dev/null
+++ b/src/components/Tool/Appeal/Modals/EditAppealHeaderInfoModal/EditAppealHeaderInfoModal.tsx
@@ -0,0 +1,161 @@
+import React, { ReactElement } from 'react';
+import {
+ DialogActions,
+ DialogContent,
+ FormHelperText,
+ TextField,
+} from '@mui/material';
+import { Box } from '@mui/system';
+import { Formik } from 'formik';
+import { useSnackbar } from 'notistack';
+import { useTranslation } from 'react-i18next';
+import * as yup from 'yup';
+import { AppealFieldsFragment } from 'pages/accountLists/[accountListId]/tools/GetAppeals.generated';
+import { FieldWrapper } from 'src/components/Shared/Forms/FieldWrapper';
+import {
+ CancelButton,
+ SubmitButton,
+} from 'src/components/common/Modal/ActionButtons/ActionButtons';
+import Modal from 'src/components/common/Modal/Modal';
+import { useAccountListId } from 'src/hooks/useAccountListId';
+import i18n from 'src/lib/i18n';
+import { useUpdateAppealMutation } from './EditAppeal.generated';
+
+interface EditAppealHeaderInfoModalProps {
+ handleClose: () => void;
+ appealInfo: AppealFieldsFragment;
+}
+
+export type EditAppealFormikSchema = {
+ name: string;
+ amount: number;
+};
+
+const EditAppealSchema: yup.SchemaOf = yup.object({
+ name: yup.string().required(i18n.t('Please enter a name')),
+ amount: yup
+ .number()
+ .required(i18n.t('Please enter a goal'))
+ .typeError(i18n.t('Appeal amount must be a valid number'))
+ .test(
+ i18n.t('Is positive?'),
+ i18n.t('Must use a positive number for appeal amount'),
+ (value) => !value || parseFloat(value as unknown as string) > 0,
+ ),
+});
+
+export const EditAppealHeaderInfoModal: React.FC<
+ EditAppealHeaderInfoModalProps
+> = ({ appealInfo, handleClose }) => {
+ const { t } = useTranslation();
+ const accountListId = useAccountListId();
+ const { enqueueSnackbar } = useSnackbar();
+ const [UpdateAppeal] = useUpdateAppealMutation();
+
+ const onSubmit = async (attributes: EditAppealFormikSchema) => {
+ await UpdateAppeal({
+ variables: {
+ input: {
+ accountListId: accountListId ?? '',
+ attributes: {
+ id: appealInfo.id,
+ name: attributes.name,
+ amount: attributes.amount,
+ },
+ },
+ },
+ update: (cache) => {
+ cache.modify({
+ id: cache.identify({ __typename: 'Appeal', id: appealInfo.id }),
+ fields: {
+ name() {
+ return attributes.name;
+ },
+ amount() {
+ return attributes.amount;
+ },
+ },
+ });
+ },
+ onCompleted: () => {
+ enqueueSnackbar(t('Successfully updated the appeal'), {
+ variant: 'success',
+ });
+ handleClose();
+ },
+ onError: () => {
+ enqueueSnackbar(t('Failed to update the appeal'), {
+ variant: 'error',
+ });
+ },
+ });
+ };
+
+ return (
+
+
+ {({
+ values: { name, amount },
+ handleChange,
+ handleSubmit,
+ isSubmitting,
+ isValid,
+ errors,
+ }): ReactElement => (
+
+ )}
+
+
+ );
+};