formik#FormikHelpers TypeScript Examples

The following examples show how to use formik#FormikHelpers. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: SQFormScrollableCardsMenuWrapper.stories.tsx    From SQForm with MIT License 7 votes vote down vote up
function ScrollableDetails(): React.ReactElement {
  const initialValues = {
    name: '',
  };

  const validationSchema = Yup.object({
    name: Yup.string().required().min(12),
  });

  const handleSubmit = (
    values: typeof initialValues,
    formikHelpers: FormikHelpers<typeof initialValues>
  ) => {
    window.alert(JSON.stringify(values, null, 2));
    formikHelpers.setSubmitting(false);
    formikHelpers.resetForm();
  };

  return (
    <SQFormScrollableCard
      isHeaderDisabled={true}
      isSelfBounding={true}
      initialValues={initialValues}
      onSubmit={handleSubmit}
      shouldRequireFieldUpdates={true}
      validationSchema={validationSchema}
    >
      <SQFormTextField name="name" label="Name" size={12} />
    </SQFormScrollableCard>
  );
}
Example #2
Source File: SQFormScrollableCardsMenuWrapper.stories.tsx    From SQForm with MIT License 7 votes vote down vote up
function ScrollablePermissions(): React.ReactElement {
  const initialValues = {
    isAdmin: false,
  };

  const validationSchema = Yup.object({
    isAdmin: Yup.boolean(),
  });

  const handleSubmit = (
    values: typeof initialValues,
    formikHelpers: FormikHelpers<typeof initialValues>
  ) => {
    window.alert(JSON.stringify(values, null, 2));
    formikHelpers.setSubmitting(false);
    formikHelpers.resetForm();
  };

  return (
    <SQFormScrollableCard
      isHeaderDisabled={true}
      isSelfBounding={true}
      initialValues={initialValues}
      onSubmit={handleSubmit}
      shouldRequireFieldUpdates={true}
      validationSchema={validationSchema}
    >
      <SQFormCheckbox name="isAdmin" label="Admin" size={12} />
    </SQFormScrollableCard>
  );
}
Example #3
Source File: useResetPasswordFormik.tsx    From bouncecode-cms with GNU General Public License v3.0 7 votes vote down vote up
function useResetPasswordFormik(
  onSubmit: (
    values: FormikValues,
    formikHelpers: FormikHelpers<FormikValues>,
  ) => void | Promise<any>,
  options?: Partial<FormikConfig<FormikValues>>,
) {
  const {enqueueSnackbar} = useSnackbar();

  const formik = useFormik({
    ...options,
    initialValues: {
      ...initialValues,
      ...options?.initialValues,
    },
    validationSchema,
    onSubmit,
  });

  useEffect(() => {
    if (formik.submitCount > 0 && !formik.isSubmitting && !formik.isValid) {
      enqueueSnackbar('누락된 입력 항목을 확인해주세요.', {
        variant: 'error',
      });
    }
  }, [formik.submitCount, formik.isSubmitting]);

  return formik;
}
Example #4
Source File: useSignUpFormik.tsx    From bouncecode-cms with GNU General Public License v3.0 6 votes vote down vote up
function useSignUpFormik(
  onSubmit: (
    values: FormikValues,
    formikHelpers: FormikHelpers<FormikValues>,
  ) => void | Promise<any>,
  options?: Partial<FormikConfig<FormikValues>>,
) {
  const {enqueueSnackbar} = useSnackbar();

  const formik = useFormik({
    ...options,
    initialValues: {
      ...initialValues,
      ...options?.initialValues,
    },
    validationSchema,
    onSubmit,
  });

  useEffect(() => {
    if (formik.submitCount > 0 && !formik.isSubmitting && !formik.isValid) {
      enqueueSnackbar('누락된 입력 항목을 확인해주세요.', {
        variant: 'error',
      });
    }
  }, [formik.submitCount, formik.isSubmitting]);

  return formik;
}
Example #5
Source File: useSignInFormik.tsx    From bouncecode-cms with GNU General Public License v3.0 6 votes vote down vote up
function useSigninFormik(
  onSubmit: (
    values: FormikValues,
    formikHelpers: FormikHelpers<FormikValues>,
  ) => void | Promise<any>,
  options?: Partial<FormikConfig<FormikValues>>,
) {
  const {enqueueSnackbar} = useSnackbar();

  const formik = useFormik({
    ...options,
    initialValues: {
      ...initialValues,
      ...options?.initialValues,
    },
    validationSchema,
    onSubmit,
  });

  useEffect(() => {
    if (formik.submitCount > 0 && !formik.isSubmitting && !formik.isValid) {
      enqueueSnackbar('누락된 입력 항목을 확인해주세요.', {
        variant: 'error',
      });
    }
  }, [formik.submitCount, formik.isSubmitting]);

  return formik;
}
Example #6
Source File: useResetPasswordSubmitCallback.tsx    From bouncecode-cms with GNU General Public License v3.0 6 votes vote down vote up
function useResetPasswordSubmitCallback() {
  const {enqueueSnackbar} = useSnackbar();

  return useCallback(
    async (
      values: FormikValues,
      formikHelpers: FormikHelpers<FormikValues>,
    ) => {
      try {
        // await firebase.auth().sendPasswordResetEmail(values.email);
        enqueueSnackbar('이메일을 확인해주세요.', {variant: 'success'});
      } catch (e) {
        console.error(e);
        enqueueSnackbar(e.message, {variant: 'error'});
      }
    },
    [],
  );
}
Example #7
Source File: AvailableSubnetsControl.tsx    From assisted-ui-lib with Apache License 2.0 6 votes vote down vote up
useAutoSelectSingleAvailableSubnet = (
  hasNoMachineNetworks: boolean,
  setFieldValue: FormikHelpers<NetworkConfigurationValues>['setFieldValue'],
  cidr: MachineNetwork['cidr'],
  clusterId: string,
) => {
  useEffect(() => {
    if (hasNoMachineNetworks) {
      setFieldValue('machineNetworks', [{ cidr, clusterId }], true);
    }
  }, [hasNoMachineNetworks, cidr, clusterId, setFieldValue]);
}
Example #8
Source File: SQForm.tsx    From SQForm with MIT License 5 votes vote down vote up
function SQForm<Values extends FormikValues>({
  children,
  enableReinitialize = false,
  initialValues,
  muiGridProps = {},
  onSubmit,
  validationSchema,
}: SQFormProps<Values>): JSX.Element {
  const initialErrors = useInitialRequiredErrors(
    validationSchema,
    initialValues
  );

  // HACK: This is a workaround for: https://github.com/mui-org/material-ui-pickers/issues/2112
  // Remove this reset handler when the issue is fixed.
  const handleReset = () => {
    document &&
      document.activeElement &&
      (document.activeElement as HTMLElement).blur();
  };

  const handleSubmit = useDebouncedCallback(
    (values: Values, formikHelpers: FormikHelpers<Values>) =>
      onSubmit(values, formikHelpers),
    500,
    {leading: true, trailing: false}
  );

  return (
    <Formik<Values>
      enableReinitialize={enableReinitialize}
      initialErrors={initialErrors}
      initialValues={initialValues}
      onSubmit={handleSubmit}
      onReset={handleReset}
      validationSchema={validationSchema}
      validateOnMount={true}
    >
      {(_props) => {
        return (
          <Form>
            <Grid
              {...muiGridProps}
              container
              spacing={muiGridProps.spacing ?? 2}
            >
              {children}
            </Grid>
          </Form>
        );
      }}
    </Formik>
  );
}
Example #9
Source File: SingleInputForm.tsx    From bada-frame with GNU General Public License v3.0 5 votes vote down vote up
export default function SingleInputForm(props: Props) {
    const [loading, SetLoading] = useState(false);
    const [showPassword, setShowPassword] = useState(false);

    const submitForm = async (
        values: formValues,
        { setFieldError }: FormikHelpers<formValues>
    ) => {
        SetLoading(true);
        await props.callback(values.passphrase, setFieldError);
        SetLoading(false);
    };
    return (
        <Formik<formValues>
            initialValues={{ passphrase: '' }}
            onSubmit={submitForm}
            validationSchema={Yup.object().shape({
                passphrase: Yup.string().required(constants.REQUIRED),
            })}
            validateOnChange={false}
            validateOnBlur={false}>
            {({ values, touched, errors, handleChange, handleSubmit }) => (
                <Form noValidate onSubmit={handleSubmit}>
                    <Form.Group>
                        <Group>
                            <Form.Control
                                type={showPassword ? 'text' : props.fieldType}
                                placeholder={props.placeholder}
                                value={values.passphrase}
                                onChange={handleChange('passphrase')}
                                isInvalid={Boolean(
                                    touched.passphrase && errors.passphrase
                                )}
                                disabled={loading}
                                autoFocus
                            />
                            {props.fieldType === 'password' && (
                                <Button
                                    type="button"
                                    onClick={() =>
                                        setShowPassword(!showPassword)
                                    }>
                                    {showPassword ? (
                                        <VisibilityOff />
                                    ) : (
                                        <Visibility />
                                    )}
                                </Button>
                            )}
                            <Form.Control.Feedback type="invalid">
                                {errors.passphrase}
                            </Form.Control.Feedback>
                        </Group>
                    </Form.Group>
                    <SubmitButton
                        buttonText={props.buttonText}
                        loading={loading}
                    />

                    <br />
                </Form>
            )}
        </Formik>
    );
}
Example #10
Source File: UpdateBirthdayModal.tsx    From frontend with MIT License 5 votes vote down vote up
function UpdateBirthdayModal({
  isOpen,
  handleClose,
  person,
}: {
  isOpen: boolean
  handleClose: (data?: Person) => void
  person: UpdatePerson
}) {
  const { t } = useTranslation()

  const dateBefore18Years = new Date(new Date().setFullYear(new Date().getFullYear() - 18))

  const initialValues: BirthdayFormData = {
    birthday: format(new Date(person.birthday ?? dateBefore18Years), formatString),
  }

  const mutation = useMutation<AxiosResponse<Person>, AxiosError<ApiErrors>, UpdatePerson>({
    mutationFn: updateCurrentPerson(),
    onError: () => AlertStore.show(t('common:alerts.error'), 'error'),
    onSuccess: () => AlertStore.show(t('common:alerts.success'), 'success'),
  })

  const onSubmit = async (
    values: BirthdayFormData,
    { setFieldError }: FormikHelpers<BirthdayFormData>,
  ) => {
    try {
      const birthDate = new Date(values?.birthday)
      await mutation.mutateAsync({ ...person, birthday: birthDate }).then((data) => {
        handleClose(data.data)
      })
    } catch (error) {
      console.error(error)
      if (isAxiosError(error)) {
        const { response } = error as AxiosError<ApiErrors>
        response?.data.message.map(({ property, constraints }) => {
          setFieldError(property, t(matchValidator(constraints)))
        })
      }
    }
  }

  return (
    <StyledModal
      open={isOpen}
      onClose={() => handleClose()}
      aria-labelledby="modal-modal-title"
      aria-describedby="modal-modal-description">
      <Box className={classes.modal}>
        <IconButton className={classes.close} onClick={() => handleClose()}>
          <CloseIcon />
        </IconButton>
        <h2>Обнови рожден ден</h2>
        <GenericForm<BirthdayFormData>
          onSubmit={onSubmit}
          initialValues={initialValues}
          validationSchema={validationSchema}>
          <Grid container spacing={3}>
            <Grid item xs={12} sm={8}>
              <FormTextField
                type="date"
                name="birthday"
                label="Кога е твоят рожден ден?"
                InputLabelProps={{
                  shrink: true,
                }}
              />
            </Grid>
            <Grid item xs={6}>
              <SubmitButton fullWidth />
            </Grid>
          </Grid>
        </GenericForm>
      </Box>
    </StyledModal>
  )
}
Example #11
Source File: useCommentCreateFormik.tsx    From bouncecode-cms with GNU General Public License v3.0 5 votes vote down vote up
export function useCommentCreateFormik(
  postId: string,
  options?: Partial<FormikConfig<FormikValues>>,
) {
  const {enqueueSnackbar} = useSnackbar();
  const [create] = useCommentCreateMutation({
    onCompleted: () => {
      formik.handleReset(null);
    },
  });

  const onSubmit = async (
    values: FormikValues,
    formikHelpers: FormikHelpers<FormikValues>,
  ) => {
    return create({
      variables: {
        data: {
          postId,
          text: values.text,
          payload: {},
        },
      },
      refetchQueries: [CommentsDocument, CommentStatDocument],
    });
  };

  const formik = useFormik({
    ...options,
    initialValues: {
      ...initialValues,
      ...options?.initialValues,
    },
    validationSchema,
    onSubmit,
  });

  useEffect(() => {
    if (formik.submitCount > 0 && !formik.isSubmitting && !formik.isValid) {
      enqueueSnackbar('누락된 입력 항목을 확인해주세요.', {
        variant: 'error',
      });
    }
  }, [formik.submitCount, formik.isSubmitting]);

  return formik;
}
Example #12
Source File: SQForm.stories.tsx    From SQForm with MIT License 5 votes vote down vote up
handleSubmit = <TValues extends unknown>(
  values: TValues,
  actions: FormikHelpers<TValues>
) => {
  window.alert(JSON.stringify(values, null, 2));
  actions.setSubmitting(false);
  actions.resetForm();
}
Example #13
Source File: DiscoveryImageForm.tsx    From assisted-ui-lib with Apache License 2.0 5 votes vote down vote up
DiscoveryImageForm: React.FC<DiscoveryImageFormProps> = ({
  cluster,
  onCancel,
  onSuccess,
}) => {
  const { infraEnv, error: infraEnvError, isLoading } = useInfraEnv(cluster.id);
  const cancelSourceRef = React.useRef<CancelTokenSource>();
  const dispatch = useDispatch();
  const ocmPullSecret = usePullSecret();

  React.useEffect(() => {
    cancelSourceRef.current = Axios.CancelToken.source();
    return () => cancelSourceRef.current?.cancel('Image generation cancelled by user.');
  }, []);

  const handleCancel = () => {
    dispatch(forceReload());
    onCancel();
  };

  const handleSubmit = async (
    formValues: DiscoveryImageFormValues,
    formikActions: FormikHelpers<DiscoveryImageFormValues>,
  ) => {
    if (cluster.id && infraEnv?.id) {
      try {
        const { updatedCluster } = await DiscoveryImageFormService.update(
          cluster.id,
          infraEnv.id,
          cluster.kind,
          formValues,
          ocmPullSecret,
        );
        onSuccess();
        dispatch(updateCluster(updatedCluster));
      } catch (error) {
        handleApiError(error, () => {
          formikActions.setStatus({
            error: {
              title: 'Failed to download the discovery Image',
              message: getErrorMessage(error),
            },
          });
        });
      }
    }
  };

  if (isLoading) {
    return <LoadingState></LoadingState>;
  } else if (infraEnvError) {
    return <ErrorState></ErrorState>;
  }

  return (
    <DiscoveryImageConfigForm
      onCancel={handleCancel}
      handleSubmit={handleSubmit}
      sshPublicKey={infraEnv?.sshAuthorizedKey}
      httpProxy={infraEnv?.proxy?.httpProxy}
      httpsProxy={infraEnv?.proxy?.httpsProxy}
      noProxy={infraEnv?.proxy?.noProxy}
      imageType={infraEnv?.type}
    />
  );
}
Example #14
Source File: AdditionalNTPSourcesDialog.tsx    From assisted-ui-lib with Apache License 2.0 4 votes vote down vote up
AdditionalNTPSourcesForm: React.FC<AdditionalNTPSourcesFormProps> = ({
  additionalNtpSource,
  onClose,
  onAdditionalNtpSource,
}) => {
  const initialValues: V2ClusterUpdateParams = {
    additionalNtpSource: additionalNtpSource || '',
  };

  const validationSchema = Yup.object().shape({
    additionalNtpSource: ntpSourceValidationSchema.required(),
  });

  const handleSubmit = async (
    values: V2ClusterUpdateParams,
    formikHelpers: FormikHelpers<V2ClusterUpdateParams>,
  ) => {
    formikHelpers.setStatus({ error: null });
    if (onAdditionalNtpSource && values.additionalNtpSource) {
      const onError = (message: string) =>
        formikHelpers.setStatus({
          error: {
            title: 'Failed to add NTP sources',
            message,
          },
        });
      onAdditionalNtpSource(values.additionalNtpSource, onError);
    }
    onClose();
  };

  return (
    <Formik
      initialValues={initialValues}
      initialTouched={{ additionalNtpSource: true }}
      initialStatus={{ error: null }}
      validationSchema={validationSchema}
      onSubmit={handleSubmit}
    >
      {({ submitForm, status, setStatus, isSubmitting, isValid, dirty }) => {
        return (
          <>
            <ModalBoxBody>
              <Form>
                {status.error && (
                  <Alert
                    variant={AlertVariant.danger}
                    title={status.error.title}
                    actionClose={
                      <AlertActionCloseButton onClose={() => setStatus({ error: null })} />
                    }
                    isInline
                  >
                    {status.error.message}
                  </Alert>
                )}
                <AdditionalNTPSourcesField
                  name="additionalNtpSource"
                  label="Additional NTP Sources"
                  helperText="A comma separated list of IP or domain names of the NTP pools or servers. Additional NTP sources are added to all hosts to ensure all hosts clocks are synchronized with a valid NTP server. It may take a few minutes for the new NTP sources to sync."
                  isRequired
                />
              </Form>
            </ModalBoxBody>
            <ModalBoxFooter>
              <Button
                key="submit"
                onClick={submitForm}
                isDisabled={isSubmitting || !isValid || !dirty}
                isLoading={isSubmitting}
              >
                {isSubmitting ? 'Adding...' : 'Add'}
              </Button>
              <Button key="cancel" variant="link" onClick={onClose}>
                Cancel
              </Button>
            </ModalBoxFooter>
          </>
        );
      }}
    </Formik>
  );
}
Example #15
Source File: ClusterDetailsForm.tsx    From assisted-ui-lib with Apache License 2.0 4 votes vote down vote up
ClusterDetailsForm: React.FC<ClusterDetailsFormProps> = (props) => {
  const {
    cluster,
    infraEnv,
    pullSecret,
    managedDomains,
    ocpVersions,
    usedClusterNames = [],
    moveNext,
    handleClusterUpdate,
    handleClusterCreate,
    navigation,
  } = props;

  const featureSupportLevels = useFeatureSupportLevel();
  const handleSubmit = React.useCallback(
    async (values: OcmClusterDetailsValues) => {
      const params = ClusterDetailsService.getClusterCreateParams(values);
      if (cluster) {
        await handleClusterUpdate(cluster.id, params);
      } else {
        await handleClusterCreate(params);
      }
    },
    [cluster, handleClusterCreate, handleClusterUpdate],
  );

  const handleOnNext = (
    dirty: boolean,
    submitForm: FormikHelpers<unknown>['submitForm'],
    cluster?: Cluster,
  ): (() => Promise<void> | void) => {
    if (!dirty && !isUndefined(cluster) && canNextClusterDetails({ cluster })) {
      return moveNext;
    }
    return submitForm;
  };

  const initialValues = React.useMemo(
    () =>
      ClusterDetailsService.getClusterDetailsInitialValues({
        infraEnv,
        cluster,
        pullSecret,
        managedDomains,
        ocpVersions,
      }),
    [cluster, pullSecret, managedDomains, ocpVersions, infraEnv],
  );

  const validationSchema = getClusterDetailsValidationSchema({
    usedClusterNames,
    featureSupportLevels,
    pullSecretSet: cluster?.pullSecretSet,
    ocpVersions,
    isOcm: true,
  });

  return (
    <Formik
      initialValues={initialValues}
      validate={getRichTextValidation(validationSchema)}
      onSubmit={handleSubmit}
    >
      {({ submitForm, isSubmitting, isValid, dirty, setFieldValue, errors, touched }) => {
        const errorFields = getFormikErrorFields(errors, touched);
        const toggleRedHatDnsService = (checked: boolean) =>
          setFieldValue('baseDnsDomain', checked ? managedDomains.map((d) => d.domain)[0] : '');

        const form = (
          <>
            <Grid hasGutter>
              <GridItem>
                <ClusterWizardStepHeader
                  extraItems={<ClusterWizardHeaderExtraActions cluster={cluster} />}
                >
                  Cluster details
                </ClusterWizardStepHeader>
              </GridItem>
              <GridItem span={12} lg={10} xl={9} xl2={7}>
                <OcmClusterDetailsFormFields
                  toggleRedHatDnsService={toggleRedHatDnsService}
                  versions={ocpVersions}
                  canEditPullSecret={!cluster?.pullSecretSet}
                  forceOpenshiftVersion={cluster?.openshiftVersion}
                  defaultPullSecret={pullSecret}
                  isOcm={!!ocmClient}
                  managedDomains={managedDomains}
                  isPullSecretSet={cluster?.pullSecretSet ? cluster.pullSecretSet : false}
                  clusterExists={!!cluster}
                />
              </GridItem>
            </Grid>
          </>
        );
        const footer = (
          <ClusterWizardFooter
            cluster={cluster}
            errorFields={errorFields}
            isSubmitting={isSubmitting}
            isNextDisabled={
              !(
                !isSubmitting &&
                isValid &&
                (dirty || (cluster && canNextClusterDetails({ cluster })))
              )
            }
            onNext={handleOnNext(dirty, submitForm, cluster)}
          />
        );
        return (
          <ClusterWizardStep navigation={navigation} footer={footer}>
            {form}
          </ClusterWizardStep>
        );
      }}
    </Formik>
  );
}
Example #16
Source File: SupportForm.tsx    From frontend with MIT License 4 votes vote down vote up
export default function SupportForm() {
  const { t } = useTranslation()

  const formRef = useRef<FormikProps<SupportFormData>>(null)
  const [activeStep, setActiveStep] = useState<Steps>(Steps.ROLES)
  const [failedStep, setFailedStep] = useState<Steps>(Steps.NONE)

  const mutation = useMutation<
    AxiosResponse<SupportRequestResponse>,
    AxiosError<ApiErrors>,
    SupportRequestInput
  >({
    mutationFn: createSupportRequest,
    onError: () => AlertStore.show(t('common:alerts.error'), 'error'),
    onSuccess: () => AlertStore.show(t('common:alerts.message-sent'), 'success'),
  })

  const handleBack = () => {
    setActiveStep((prevActiveStep) => prevActiveStep - 1)
  }

  const handleSubmit = async (values: SupportFormData, actions: FormikHelpers<SupportFormData>) => {
    if (isLastStep(activeStep, steps)) {
      const errors = await actions.validateForm()
      const hasErrors = !!Object.keys(errors).length
      if (hasErrors) {
        setFailedStep(Steps.PERSON)
        return
      }
      setActiveStep((prevActiveStep) => prevActiveStep + 1)
      setFailedStep(Steps.NONE)
      try {
        const { person, ...supportData } = values
        await mutation.mutateAsync({ person, supportData })
        actions.resetForm()
        if (window) {
          window.scrollTo({ top: 0, behavior: 'smooth' })
        }
      } catch (error) {
        console.error(error)
        if (isAxiosError(error)) {
          const { response } = error as AxiosError<ApiErrors>
          response?.data.message.map(({ property, constraints }) => {
            actions.setFieldError(property, t(matchValidator(constraints)))
          })
        }
      }

      return
    }

    actions.setTouched({})
    actions.setSubmitting(false)
    switch (activeStep) {
      case Steps.ROLES:
        {
          const errors = await actions.validateForm()
          if (errors.roles) {
            setFailedStep(Steps.ROLES)
            return
          }
          setActiveStep((prevActiveStep) => prevActiveStep + 1)
          setFailedStep(Steps.NONE)
        }
        break
      case Steps.QUESTIONS:
        {
          const errors = await actions.validateForm()
          let hasErrors = false
          const questions = Object.entries(values.roles)
            .filter(([, value]) => value)
            .map(([key]) => key)

          Object.keys(errors).forEach((error) => {
            if (questions.includes(error)) {
              hasErrors = true
            }
          })

          if (hasErrors) {
            setFailedStep(Steps.QUESTIONS)
            return
          }
          setActiveStep((prevActiveStep) => prevActiveStep + 1)
          setFailedStep(Steps.NONE)
        }
        break
      case Steps.PERSON:
        {
          const errors = await actions.validateForm()
          if (errors.person) {
            setFailedStep(Steps.PERSON)
            return
          }
          setActiveStep((prevActiveStep) => prevActiveStep + 1)
          setFailedStep(Steps.NONE)
        }
        break
      default:
        return 'Unknown step'
    }
  }

  const isStepFailed = (step: Steps | number): boolean => {
    return step === failedStep
  }

  const isLastStep = (activeStep: number, steps: StepType[]): boolean => {
    return activeStep === steps.length - 2
  }

  const isThankYouStep = (activeStep: number, steps: StepType[]): boolean => {
    return activeStep === steps.length - 1
  }

  return (
    <GenericForm<SupportFormData>
      onSubmit={handleSubmit}
      initialValues={initialValues}
      validationSchema={validationSchema[activeStep]}
      innerRef={formRef}>
      <Hidden mdDown>
        <Stepper
          alternativeLabel
          activeStep={activeStep}
          connector={<StepConnector sx={{ mt: 1.5 }} />}>
          {steps.map((step, index) => (
            <Step key={index}>
              <StepLabel error={isStepFailed(index)} StepIconComponent={StepIcon}>
                {t(step.label)}
              </StepLabel>
            </Step>
          ))}
        </Stepper>
      </Hidden>
      {isThankYouStep(activeStep, steps) ? (
        steps[activeStep].component
      ) : (
        <Box sx={{ display: 'flex', justifyContent: 'center' }}>
          <Grid container justifyContent="center">
            <Grid item xs={12} sx={{ mt: 1, mb: 5 }}>
              {steps[activeStep].component}
            </Grid>
            <Grid item xs={12} sx={(theme) => ({ '& button': { minWidth: theme.spacing(12) } })}>
              <Actions
                disableBack={activeStep === 0}
                onBack={handleBack}
                loading={mutation.isLoading}
                nextLabel={
                  isLastStep(activeStep, steps) ? 'support:cta.submit' : 'support:cta.next'
                }
              />
            </Grid>
          </Grid>
        </Box>
      )}
    </GenericForm>
  )
}
Example #17
Source File: AddBenefactorForm.tsx    From frontend with MIT License 4 votes vote down vote up
export default function AddBenefactorForm({ initialValues = defaults }: BenefactorFormProps) {
  const { t } = useTranslation('benefactor')

  const mutation = useMutation<
    AxiosResponse<BenefactorResponse>,
    AxiosError<ApiErrors>,
    BenefactorInput
  >({
    mutationFn: createBenefactor,
    onError: () => AlertStore.show(t('alerts.error'), 'error'),
    onSuccess: () => AlertStore.show(t('alerts.create'), 'success'),
  })

  const router = useRouter()

  const onSubmit = async (
    values: BenefactorFormData,
    { setFieldError, resetForm }: FormikHelpers<BenefactorFormData>,
  ) => {
    try {
      const data = {
        // id: values.id,
        extCustomerId: values.extCustomerId,
        // createdAt: values.createdAt,
        // updatedAt: values.updatedAt,
        person: values.person,
      }
      await mutation.mutateAsync(data)
      resetForm()
      router.push(routes.admin.benefactor.index)
    } catch (error) {
      console.error(error)
      if (isAxiosError(error)) {
        const { response } = error as AxiosError<ApiErrors>
        response?.data.message.map(({ property, constraints }) => {
          setFieldError(property, t(matchValidator(constraints)))
        })
      }
    }
  }
  return (
    <Grid
      container
      direction="column"
      component="section"
      sx={{
        maxWidth: '700px',
        margin: '0 auto',
      }}>
      <GenericForm
        onSubmit={onSubmit}
        initialValues={initialValues}
        validationSchema={validationSchema}>
        <Box sx={{ marginTop: '5%', height: '62.6vh' }}>
          <Grid container spacing={3}>
            <Grid item xs={12}>
              <Typography variant="h6">{t('form-heading')}</Typography>
            </Grid>
            {/* <Grid item xs={12} sm={4}>
            <FormTextField
              type="text"
              label="auth:fields.id"
              name="id"
              autoComplete="id"
            />
          </Grid> */}
            <Grid item xs={12} sm={4}>
              <FormTextField
                type="text"
                label={t('customerId')}
                name="extCustomerId"
                autoComplete="extCustomerId"
              />
            </Grid>
            <Grid item xs={12} sm={4}>
              <FormTextField
                type="text"
                label={t('personId')}
                name="person"
                autoComplete="person"
              />
            </Grid>
            <Grid item xs={12}>
              <SubmitButton fullWidth label={t('cta.submit')} />
            </Grid>
            <Grid item xs={6}>
              <Link href={routes.admin.benefactor.index}>
                <Button>{t('cta.cancel')}</Button>
              </Link>
            </Grid>
          </Grid>
        </Box>
      </GenericForm>
    </Grid>
  )
}
Example #18
Source File: AddHostModal.tsx    From assisted-ui-lib with Apache License 2.0 4 votes vote down vote up
AddHostModal: React.FC<AddHostModalProps> = ({
  isOpen,
  onClose,
  infraEnv,
  agentClusterInstall,
  onCreateBMH,
  onSaveISOParams,
  usedHostnames,
  isBMPlatform,
}) => {
  const hasDHCP = infraEnv.metadata?.labels?.networkType !== 'static';
  const sshPublicKey = infraEnv.spec?.sshAuthorizedKey || agentClusterInstall?.spec?.sshPublicKey;
  const { httpProxy, httpsProxy, noProxy } = infraEnv.spec?.proxy || {};

  const areIsoDataAvailable = !!sshPublicKey || !!httpProxy || !!httpsProxy || !!noProxy;
  const isoDialog = areIsoDataAvailable ? 'iso-download' : 'iso-config';
  const [dialogType, setDialogType] = React.useState<AddHostModalStepType>(isoDialog);

  const handleIsoConfigSubmit = async (
    values: DiscoveryImageFormValues,
    formikActions: FormikHelpers<DiscoveryImageFormValues>,
  ) => {
    try {
      await onSaveISOParams(values);
      setDialogType('iso-download');
    } catch (error) {
      formikActions.setStatus({
        error: {
          title: 'Failed to download the discovery Image',
          message: error, // TODO(mlibra): parse it better!!
        },
      });
    }
  };

  return (
    <Modal
      aria-label="Add host dialog"
      title="Add host"
      isOpen={isOpen}
      onClose={onClose}
      variant={ModalVariant.small}
      hasNoBodyWrapper
      id="add-host-modal"
    >
      <ModalBoxHeader>
        <Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
          <FlexItem>
            <Radio
              id="iso"
              name="type"
              label="Discovery ISO"
              isChecked={dialogType !== 'bmc'}
              onChange={(checked) => setDialogType(checked ? isoDialog : 'bmc')}
            />
          </FlexItem>
          <FlexItem spacer={{ default: isBMPlatform ? 'spacerXl' : 'spacerSm' }} />
          <FlexItem>
            <Tooltip
              hidden={isBMPlatform}
              content="To enable the host’s baseboard management controller (BMC) on the hub cluster,deploy the hub cluster on vSphere, BareMetal, OpenStack, or platform-agnostic (none type)."
            >
              <Radio
                id="bmc"
                name="type"
                label="Baseboard Management Controller (BMC)"
                isChecked={dialogType === 'bmc'}
                onChange={(checked) => setDialogType(checked ? 'bmc' : isoDialog)}
                isDisabled={!isBMPlatform}
              />
            </Tooltip>
          </FlexItem>
        </Flex>
      </ModalBoxHeader>
      {dialogType === 'iso-config' && (
        <DiscoveryImageConfigForm
          onCancel={onClose}
          handleSubmit={handleIsoConfigSubmit}
          hideDiscoveryImageType={true} // So far configured by env variable on backend
          imageType="full-iso" // So far the only option for CIM
          sshPublicKey={sshPublicKey}
          httpProxy={httpProxy}
          httpsProxy={httpsProxy}
          noProxy={noProxy}
          hasDHCP={hasDHCP}
        />
      )}
      {dialogType === 'iso-download' && (
        <DownloadIso
          onClose={onClose}
          downloadUrl={infraEnv?.status?.isoDownloadURL}
          onReset={() => setDialogType('iso-config')}
          hasDHCP={hasDHCP}
        />
      )}
      {dialogType === 'bmc' && (
        <BMCForm
          onCreateBMH={onCreateBMH}
          onClose={onClose}
          hasDHCP={hasDHCP}
          infraEnv={infraEnv}
          usedHostnames={usedHostnames}
        />
      )}
    </Modal>
  );
}
Example #19
Source File: EditBenefactorForm.tsx    From frontend with MIT License 4 votes vote down vote up
export default function EditBenefactorForm({ id, initialValues = defaults }: BenefactorFormProps) {
  const { t } = useTranslation('benefactor')

  const mutation = useMutation<
    AxiosResponse<BenefactorResponse>,
    AxiosError<ApiErrors>,
    EditBenefactorProp
  >({
    mutationFn: editBenefactor,
    onError: () => AlertStore.show(t('alerts.error'), 'error'),
    onSuccess: () => AlertStore.show(t('alerts.create'), 'success'),
  })

  const router = useRouter()

  const onSubmit = async (
    values: BenefactorFormData,
    { setFieldError }: FormikHelpers<BenefactorFormData>,
  ) => {
    try {
      const data = {
        extCustomerId: values.extCustomerId,
        person: values.person,
      }
      await mutation.mutateAsync({
        id,
        data,
      })
      router.push(routes.admin.benefactor.index)
    } catch (error) {
      console.error(error)
      if (isAxiosError(error)) {
        const { response } = error as AxiosError<ApiErrors>
        response?.data.message.map(({ property, constraints }) => {
          setFieldError(property, t(matchValidator(constraints)))
        })
      }
    }
  }

  return (
    <Grid
      container
      direction="column"
      component="section"
      sx={{
        maxWidth: '700px',
        margin: '0 auto',
        padding: '30px',
        textAlign: 'center',
      }}>
      <GenericForm
        enableReinitialize={true}
        onSubmit={onSubmit}
        initialValues={initialValues}
        validationSchema={validationSchema}>
        <Box sx={{ marginTop: '5%', height: '62.6vh' }}>
          <Typography variant="h5" component="h2" sx={{ marginBottom: 2, textAlign: 'center' }}>
            {t('edit-form-heading')}
          </Typography>
          <Grid container spacing={2} sx={{ width: 600, margin: '0 auto' }}>
            <Grid item xs={12} />
            <Grid item xs={12} sm={4}>
              <FormTextField
                type="text"
                label={t('customerId')}
                name="extCustomerId"
                autoComplete="extCustomerId"
              />
            </Grid>
            <Grid item xs={12} sm={4}>
              <FormTextField
                type="text"
                label={t('personId')}
                name="person"
                autoComplete="personId"
              />
            </Grid>
            <Grid item xs={6}>
              <Button fullWidth variant="contained" type="submit" color="secondary">
                {t('cta.submit')}
              </Button>
            </Grid>
            <Grid item xs={6}>
              <LinkButton
                fullWidth
                variant="contained"
                color="primary"
                href={routes.admin.benefactor.index}>
                {t('cta.cancel')}
              </LinkButton>
            </Grid>
          </Grid>
        </Box>
      </GenericForm>
    </Grid>
  )
}
Example #20
Source File: CampaignForm.tsx    From frontend with MIT License 4 votes vote down vote up
export default function CampaignForm({ initialValues = defaults }: CampaignFormProps) {
  const { t } = useTranslation()
  const router = useRouter()
  const [coordinator, setCoordinator] = useState<PersonFormData>()
  const [beneficiary, setBeneficiary] = useState<PersonFormData>()
  const [files, setFiles] = useState<File[]>([])
  const [roles, setRoles] = useState<FileRole[]>([])

  const mutation = useMutation<
    AxiosResponse<CampaignResponse>,
    AxiosError<ApiErrors>,
    CampaignInput
  >({
    mutationFn: useCreateCampaign(),
    onError: () => AlertStore.show(t('common:alerts.error'), 'error'),
    onSuccess: () => AlertStore.show(t('common:alerts.message-sent'), 'success'),
  })

  const fileUploadMutation = useMutation<
    AxiosResponse<CampaignUploadImage[]>,
    AxiosError<ApiErrors>,
    UploadCampaignFiles
  >({
    mutationFn: useUploadCampaignFiles(),
  })

  const onSubmit = async (
    values: CampaignFormData,
    { setFieldError, resetForm }: FormikHelpers<CampaignFormData>,
  ) => {
    try {
      const response = await mutation.mutateAsync({
        title: values.title,
        slug: createSlug(values.title),
        description: values.description,
        targetAmount: values.targetAmount,
        allowDonationOnComplete: values.allowDonationOnComplete,
        startDate: values.startDate,
        endDate: values.endDate,
        essence: '',
        campaignTypeId: values.campaignTypeId,
        beneficiaryId: values.beneficiaryId,
        coordinatorId: values.coordinatorId,
        currency: Currency.BGN,
      })
      await fileUploadMutation.mutateAsync({
        files,
        roles,
        campaignId: response.data.id,
      })
      resetForm()
      router.push(routes.campaigns.viewCampaignBySlug(response.data.slug))
    } catch (error) {
      console.error(error)
      if (isAxiosError(error)) {
        const { response } = error as AxiosError<ApiErrors>
        response?.data.message.map(({ property, constraints }) => {
          setFieldError(property, t(matchValidator(constraints)))
        })
      }
    }
  }

  return (
    <Grid container direction="column" component="section">
      <Grid item xs={12}>
        <Typography
          variant="h5"
          component="h2"
          sx={(theme) => ({
            mb: 5,
            color: theme.palette.primary.dark,
            textAlign: 'center',
          })}>
          {t('campaigns:form-heading')}
        </Typography>
      </Grid>
      <GenericForm
        onSubmit={onSubmit}
        initialValues={initialValues}
        validationSchema={validationSchema}>
        <Grid container spacing={3}>
          <Grid item xs={12}>
            <FormTextField
              type="text"
              label="campaigns:campaign.title"
              name="title"
              autoComplete="title"
            />
          </Grid>
          <Grid item xs={12} sm={6}>
            <CampaignTypeSelect />
          </Grid>
          <Grid item xs={12} sm={6}>
            <FormTextField
              type="number"
              name="targetAmount"
              autoComplete="target-amount"
              label="campaigns:campaign.amount"
            />
          </Grid>
          <Grid item xs={12} sm={6}>
            <FormTextField
              type="date"
              name="startDate"
              label="campaigns:campaign.start-date"
              helperText={null}
            />
          </Grid>
          <Grid item xs={12} sm={6}>
            <FormTextField
              type="date"
              name="endDate"
              label="campaigns:campaign.end-date"
              helperText={null}
            />
          </Grid>
          <Grid item xs={12}>
            <FormTextField
              rows={5}
              multiline
              type="text"
              name="description"
              label="campaigns:campaign.description"
              autoComplete="description"
              sx={{ '& textarea': { resize: 'vertical' } }}
            />
          </Grid>
          <Grid item xs={12} sm={6}>
            {coordinator ? (
              <Typography fontWeight="bold" variant="body2">
                {coordinator?.firstName} {coordinator?.lastName}
              </Typography>
            ) : (
              <PersonDialog
                type="coordinator"
                label={t('campaigns:campaign.coordinator.add')}
                onSubmit={async (values: PersonFormData) => {
                  setCoordinator(values)
                  console.log('new coordinator', { values })
                }}
              />
            )}
            <input type="hidden" name="coordinatorId" />
          </Grid>
          <Grid item xs={12} sm={6}>
            {beneficiary ? (
              <Typography fontWeight="bold" variant="body2">
                {beneficiary?.firstName} {beneficiary?.lastName}
              </Typography>
            ) : (
              <PersonDialog
                type="beneficiary"
                label={t('campaigns:campaign.beneficiary.add')}
                onSubmit={async (values: PersonFormData) => {
                  setBeneficiary(values)
                  console.log('new beneficiary', { values })
                }}
              />
            )}
            <input type="hidden" name="beneficiaryId" />
          </Grid>
          <Grid item xs={12}>
            <FileUpload
              buttonLabel="Добави снимки"
              onUpload={(newFiles) => {
                setFiles((prevFiles) => [...prevFiles, ...newFiles])
                setRoles((prevRoles) => [
                  ...prevRoles,
                  ...newFiles.map((file) => ({
                    file: file.name,
                    role: CampaignFileRole.background,
                  })),
                ])
              }}
            />
            <FileList
              files={files}
              filesRole={roles}
              onDelete={(deletedFile) =>
                setFiles((prevFiles) => prevFiles.filter((file) => file.name !== deletedFile.name))
              }
              onSetFileRole={(file, role) => {
                setRoles((filesRole) => [
                  ...filesRole.filter((f) => f.file !== file.name),
                  { file: file.name, role },
                ])
              }}
            />
          </Grid>
          <Grid item xs={12}>
            <AcceptTermsField name="terms" />
            <AcceptPrivacyPolicyField name="gdpr" />
          </Grid>
          <Grid item xs={12}>
            <SubmitButton
              fullWidth
              label="campaigns:cta.submit"
              loading={mutation.isLoading}
              color="info"
            />
          </Grid>
        </Grid>
      </GenericForm>
    </Grid>
  )
}
Example #21
Source File: CreateForm.tsx    From frontend with MIT License 4 votes vote down vote up
export default function CampaignForm({ initialValues = defaults }: CampaignFormProps) {
  const router = useRouter()
  const [files, setFiles] = useState<File[]>([])
  const [roles, setRoles] = useState<FileRole[]>([])
  const { t } = useTranslation()

  const mutation = useMutation<
    AxiosResponse<CampaignResponse>,
    AxiosError<ApiErrors>,
    CampaignInput
  >({
    mutationFn: useCreateCampaign(),
    onError: () => AlertStore.show(t('common:alerts.error'), 'error'),
    onSuccess: () => AlertStore.show(t('common:alerts.message-sent'), 'success'),
  })

  const fileUploadMutation = useMutation<
    AxiosResponse<CampaignUploadImage[]>,
    AxiosError<ApiErrors>,
    UploadCampaignFiles
  >({
    mutationFn: useUploadCampaignFiles(),
  })

  const onSubmit = async (
    values: CampaignFormData,
    { setFieldError }: FormikHelpers<CampaignFormData>,
  ) => {
    try {
      const response = await mutation.mutateAsync({
        title: values.title,
        slug: createSlug(values.title),
        description: values.description,
        targetAmount: values.targetAmount,
        allowDonationOnComplete: values.allowDonationOnComplete,
        startDate: values.startDate,
        endDate: values.endDate,
        essence: '',
        campaignTypeId: values.campaignTypeId,
        beneficiaryId: values.beneficiaryId,
        coordinatorId: values.coordinatorId,
        currency: Currency.BGN,
      })
      await fileUploadMutation.mutateAsync({
        files,
        roles,
        campaignId: response.data.id,
      })
      router.push(routes.admin.campaigns.index)
    } catch (error) {
      console.error(error)
      if (isAxiosError(error)) {
        const { response } = error as AxiosError<ApiErrors>
        response?.data.message.map(({ property, constraints }) => {
          setFieldError(property, t(matchValidator(constraints)))
        })
      }
    }
  }

  return (
    <Grid container direction="column" component="section">
      <Grid item xs={12}>
        <Typography
          variant="h5"
          component="h2"
          sx={(theme) => ({
            mb: 5,
            color: theme.palette.primary.dark,
            textAlign: 'center',
          })}>
          {t('campaigns:form-heading')}
        </Typography>
      </Grid>
      <GenericForm
        onSubmit={onSubmit}
        initialValues={initialValues}
        validationSchema={validationSchema}>
        <Grid container spacing={3}>
          <Grid item xs={12}>
            <FormTextField
              type="text"
              label="campaigns:campaign.title"
              name="title"
              autoComplete="title"
            />
          </Grid>
          <Grid item xs={12} sm={6}>
            <CampaignTypeSelect />
          </Grid>
          <Grid item xs={12} sm={6}>
            <FormTextField
              type="number"
              name="targetAmount"
              autoComplete="target-amount"
              label="campaigns:campaign.amount"
            />
          </Grid>
          <Grid item xs={12} sm={6}>
            <FormTextField
              type="date"
              name="startDate"
              label="campaigns:campaign.start-date"
              helperText={null}
              InputLabelProps={{
                shrink: true,
              }}
            />
          </Grid>
          <Grid item xs={12} sm={6}>
            <FormTextField
              type="date"
              name="endDate"
              label="campaigns:campaign.end-date"
              helperText={null}
              InputLabelProps={{
                shrink: true,
              }}
            />
          </Grid>
          <Grid item xs={12}>
            <FormTextField
              rows={5}
              multiline
              type="text"
              name="description"
              label="campaigns:campaign.description"
              autoComplete="description"
              sx={{ '& textarea': { resize: 'vertical' } }}
            />
          </Grid>
          <Grid item xs={12} sm={6}>
            <BeneficiarySelect />
          </Grid>
          <Grid item xs={12} sm={6}>
            <CoordinatorSelect />
          </Grid>
          <Grid item xs={12}>
            <FileUpload
              onUpload={(newFiles) => {
                setFiles((prevFiles) => [...prevFiles, ...newFiles])
                setRoles((prevRoles) => [
                  ...prevRoles,
                  ...newFiles.map((file) => ({
                    file: file.name,
                    role: CampaignFileRole.background,
                  })),
                ])
              }}
              buttonLabel="Добави документи"
            />
            <FileList
              filesRole={roles}
              files={files}
              onDelete={(deletedFile) =>
                setFiles((prevFiles) => prevFiles.filter((file) => file.name !== deletedFile.name))
              }
              onSetFileRole={(file, role) => {
                setRoles((prevRoles) => [
                  ...prevRoles.filter((f) => f.file !== file.name),
                  { file: file.name, role },
                ])
              }}
            />
          </Grid>
          <Grid item xs={12}>
            <AcceptTermsField name="terms" />
            <AcceptPrivacyPolicyField name="gdpr" />
          </Grid>
          <Grid item xs={12}>
            <SubmitButton fullWidth label="campaigns:cta.submit" loading={mutation.isLoading} />
          </Grid>
          <Link href={routes.admin.campaigns.index} passHref>
            <Button fullWidth={true}>{t('Отказ')}</Button>
          </Link>
        </Grid>
      </GenericForm>
    </Grid>
  )
}
Example #22
Source File: EditForm.tsx    From frontend with MIT License 4 votes vote down vote up
export default function EditForm({ campaign }: { campaign: CampaignResponse }) {
  const router = useRouter()
  const [files, setFiles] = useState<File[]>([])
  const [roles, setRoles] = useState<FileRole[]>([])
  const { t } = useTranslation()

  const initialValues: EditFormData = {
    title: campaign?.title || '',
    coordinatorId: campaign.coordinatorId,
    campaignTypeId: campaign.campaignTypeId,
    beneficiaryId: campaign.beneficiaryId,
    targetAmount: campaign.targetAmount || 0,
    allowDonationOnComplete: campaign.allowDonationOnComplete || false,
    startDate: format(new Date(campaign.startDate ?? new Date()), formatString),
    endDate: format(new Date(campaign.endDate ?? new Date()), formatString),
    description: campaign.description || '',
  }

  const mutation = useMutation<
    AxiosResponse<CampaignResponse>,
    AxiosError<ApiErrors>,
    CampaignInput
  >({
    mutationFn: useEditCampaign(campaign.id),
    onError: () => AlertStore.show(t('common:alerts.error'), 'error'),
    onSuccess: () => AlertStore.show(t('common:alerts.message-sent'), 'success'),
  })

  const fileUploadMutation = useMutation<
    AxiosResponse<CampaignUploadImage[]>,
    AxiosError<ApiErrors>,
    UploadCampaignFiles
  >({
    mutationFn: useUploadCampaignFiles(),
  })

  const onSubmit = async (values: EditFormData, { setFieldError }: FormikHelpers<EditFormData>) => {
    try {
      await mutation.mutateAsync({
        title: values.title,
        slug: createSlug(values.title),
        description: values.description,
        targetAmount: values.targetAmount,
        allowDonationOnComplete: campaign.allowDonationOnComplete,
        startDate: values.startDate,
        endDate: values.endDate,
        essence: campaign.essence,
        campaignTypeId: values.campaignTypeId,
        beneficiaryId: values.beneficiaryId,
        coordinatorId: values.coordinatorId,
        currency: Currency.BGN,
      })
      await fileUploadMutation.mutateAsync({
        files,
        roles,
        campaignId: campaign.id,
      })
      router.push(routes.admin.campaigns.index)
    } catch (error) {
      console.error(error)
      if (isAxiosError(error)) {
        const { response } = error as AxiosError<ApiErrors>
        response?.data.message.map(({ property, constraints }) => {
          setFieldError(property, t(matchValidator(constraints)))
        })
      }
    }
  }

  return (
    <Grid container direction="column" component="section">
      <Grid item xs={12}>
        <Typography
          variant="h5"
          component="h2"
          sx={(theme) => ({
            mb: 5,
            color: theme.palette.primary.dark,
            textAlign: 'center',
          })}>
          {t('campaigns:edit-form-heading')}
        </Typography>
      </Grid>
      <GenericForm<EditFormData>
        onSubmit={onSubmit}
        initialValues={initialValues}
        validationSchema={validationSchema}>
        <Grid container spacing={3}>
          <Grid item xs={12}>
            <FormTextField
              type="text"
              label="campaigns:campaign.title"
              name="title"
              autoComplete="title"
            />
          </Grid>
          <Grid item xs={12} sm={6}>
            <CampaignTypeSelect />
          </Grid>
          <Grid item xs={12} sm={6}>
            <FormTextField
              type="number"
              name="targetAmount"
              autoComplete="target-amount"
              label="campaigns:campaign.amount"
            />
          </Grid>
          <Grid item xs={12} sm={6}>
            <FormTextField
              type="date"
              name="startDate"
              label="campaigns:campaign.start-date"
              helperText={null}
              InputLabelProps={{
                shrink: true,
              }}
            />
          </Grid>
          <Grid item xs={12} sm={6}>
            <FormTextField
              type="date"
              name="endDate"
              label="campaigns:campaign.end-date"
              helperText={null}
              InputLabelProps={{
                shrink: true,
              }}
            />
          </Grid>
          <Grid item xs={12}>
            <FormTextField
              rows={5}
              multiline
              type="text"
              name="description"
              label="campaigns:campaign.description"
              autoComplete="description"
              sx={{ '& textarea': { resize: 'vertical' } }}
            />
          </Grid>
          <Grid item xs={12} sm={6}>
            <CoordinatorSelect />
          </Grid>
          <Grid item xs={12} sm={6}>
            <BeneficiarySelect />
          </Grid>
          <Grid item xs={12}>
            <FileUpload
              buttonLabel="Добави документи"
              onUpload={(newFiles) => {
                setFiles((prevFiles) => [...prevFiles, ...newFiles])
                setRoles((prevRoles) => [
                  ...prevRoles,
                  ...newFiles.map((file) => ({
                    file: file.name,
                    role: CampaignFileRole.background,
                  })),
                ])
              }}
            />
            <FileList
              files={files}
              filesRole={roles}
              onDelete={(deletedFile) =>
                setFiles((prevFiles) => prevFiles.filter((file) => file.name !== deletedFile.name))
              }
              onSetFileRole={(file, role) => {
                setRoles((filesRole) => [
                  ...filesRole.filter((f) => f.file !== file.name),
                  { file: file.name, role },
                ])
              }}
            />
          </Grid>
          <Grid item xs={12}>
            <SubmitButton fullWidth label="campaigns:cta.submit" loading={mutation.isLoading} />
            <Link href={routes.admin.campaigns.index}>
              <Button fullWidth={true}>{t('Отказ')}</Button>
            </Link>
          </Grid>
        </Grid>
      </GenericForm>
    </Grid>
  )
}
Example #23
Source File: ContactForm.tsx    From frontend with MIT License 4 votes vote down vote up
export default function ContactForm({ initialValues = defaults }: ContactFormProps) {
  const { t } = useTranslation()
  const mutationFn = createContactRequest
  const mutation = useMutation<
    AxiosResponse<ContactRequestResponse>,
    AxiosError<ApiErrors>,
    ContactRequestInput
  >({
    mutationFn,
    onError: () => AlertStore.show(t('common:alerts.error'), 'error'),
    onSuccess: () => AlertStore.show(t('common:alerts.message-sent'), 'success'),
  })

  const onSubmit = async (
    values: ContactFormData,
    { setFieldError, resetForm }: FormikHelpers<ContactFormData>,
  ) => {
    try {
      await mutation.mutateAsync(values)
      resetForm()
    } catch (error) {
      if (isAxiosError(error)) {
        const { response } = error as AxiosError<ApiErrors>
        response?.data.message.map(({ property, constraints }) => {
          setFieldError(property, t(matchValidator(constraints)))
        })
      }
    }
  }

  return (
    <Grid container direction="column" component="section">
      <Grid item xs={12}>
        <Typography
          variant="h5"
          component="h2"
          sx={(theme) => ({
            mb: 5,
            color: theme.palette.primary.dark,
            textAlign: 'center',
          })}>
          {t('contact:form-heading')}
        </Typography>
      </Grid>
      <GenericForm
        onSubmit={onSubmit}
        initialValues={initialValues}
        validationSchema={validationSchema}>
        <Grid container spacing={3}>
          <Grid item xs={12} sm={6}>
            <FormTextField
              type="text"
              label="auth:fields.first-name"
              name="firstName"
              autoComplete="first-name"
            />
          </Grid>
          <Grid item xs={12} sm={6}>
            <FormTextField
              type="text"
              label="auth:fields.last-name"
              name="lastName"
              autoComplete="family-name"
            />
          </Grid>
          <Grid item xs={12}>
            <FormTextField
              inputMode="email"
              type="text"
              label="auth:fields.email"
              name="email"
              autoComplete="email"
            />
          </Grid>
          <Grid item xs={12}>
            <FormTextField
              type="tel"
              name="phone"
              inputMode="tel"
              autoComplete="tel"
              label="auth:fields.phone"
            />
          </Grid>
          <Grid item xs={12}>
            <FormTextField
              type="text"
              name="company"
              label="auth:fields.company"
              autoComplete="organization"
            />
          </Grid>
          <Grid item xs={12}>
            <FormTextField
              rows={4}
              multiline
              type="text"
              name="message"
              label="auth:fields.message"
              sx={{ '& textarea': { resize: 'vertical' } }}
            />
          </Grid>
          <Grid item xs={12}>
            <AcceptTermsField name="terms" />
            <AcceptPrivacyPolicyField name="gdpr" />
          </Grid>
          <Grid item xs={12}>
            <SubmitButton fullWidth label="auth:cta.send" loading={mutation.isLoading} />
          </Grid>
        </Grid>
      </GenericForm>
    </Grid>
  )
}
Example #24
Source File: CountryForm.tsx    From frontend with MIT License 4 votes vote down vote up
export default function CountryForm({ initialValues = defaults, id }: CountryFormProps) {
  //if (id) -> edit form, else -> create form
  const { t } = useTranslation('countries')

  const createMutation = useMutation<
    AxiosResponse<CountryResponse>,
    AxiosError<ApiErrors>,
    CountryInput
  >({
    mutationFn: useCreateCountry(),
    onError: () => AlertStore.show(t('alerts.new-row.error'), 'error'),
    onSuccess: () => AlertStore.show(t('alerts.new-row.success'), 'success'),
  })

  const editMutation = useMutation<
    AxiosResponse<CountryResponse>,
    AxiosError<ApiErrors>,
    CountryEditInput
  >({
    mutationFn: useEditCountry(),
    onError: () => AlertStore.show(t('alerts.edit-row.error'), 'error'),
    onSuccess: () => AlertStore.show(t('alerts.edit-row.success'), 'success'),
  })
  const router = useRouter()

  const onSubmit = async (
    values: CountryInput,
    { setFieldError, resetForm }: FormikHelpers<CountryInput>,
  ) => {
    try {
      const data = {
        name: values.name,
        countryCode: values.countryCode.toLocaleUpperCase(),
      }
      if (id) {
        await editMutation.mutateAsync({ id, data })
      } else {
        await createMutation.mutateAsync(data)
        resetForm()
      }
      router.push(routes.admin.countries.index)
    } catch (error) {
      console.error(error)
      if (isAxiosError(error)) {
        const { response } = error as AxiosError<ApiErrors>
        response?.data.message.map(({ property, constraints }) => {
          setFieldError(property, t(matchValidator(constraints)))
        })
      }
    }
  }

  return (
    <Grid
      container
      direction="column"
      component="section"
      sx={{
        maxWidth: '700px',
        margin: '80px auto 0 auto',
      }}>
      <GenericForm
        onSubmit={onSubmit}
        initialValues={initialValues}
        validationSchema={validationSchema}>
        <Grid container spacing={3}>
          <Grid item xs={12} sm={8}>
            <FormTextField
              type="text"
              label="countries:fields.name"
              name="name"
              autoComplete="name"
            />
          </Grid>
          <Grid item xs={12} sm={4}>
            <FormTextField
              type="text"
              label="countries:fields.country-code"
              name="countryCode"
              autoComplete="country-code"
            />
          </Grid>
          {id ? (
            <>
              <Grid item xs={6}>
                <Button fullWidth variant="contained" type="submit" color="secondary">
                  {t('btns.save')}
                </Button>
              </Grid>
            </>
          ) : (
            <Grid item xs={6}>
              <SubmitButton fullWidth label="countries:btns.add" />
            </Grid>
          )}
          <Grid item xs={6}>
            <LinkButton
              fullWidth
              variant="contained"
              color="primary"
              href={routes.admin.countries.index}>
              {t('btns.cancel')}
            </LinkButton>
          </Grid>
        </Grid>
      </GenericForm>
    </Grid>
  )
}
Example #25
Source File: Form.tsx    From frontend with MIT License 4 votes vote down vote up
export default function Form() {
  const queryClient = useQueryClient()
  const router = useRouter()
  const { t } = useTranslation('expenses')

  let id = router.query.id
  let data: ExpenseResponse | undefined

  if (id) {
    id = String(id)
    data = useViewExpense(id).data
  }

  const initialValues: ExpenseInput = {
    type: data?.type || ExpenseType.none,
    status: data?.status || ExpenseStatus.pending,
    currency: data?.currency || Currency.BGN,
    amount: data?.amount || 0,
    vaultId: data?.vaultId || '',
    deleted: data?.deleted || false,
    description: data?.description || '',
    documentId: data?.documentId || '',
    approvedById: data?.approvedById || '',
  }

  const mutationFn = id ? useEditExpense(id) : useCreateExpense()

  const mutation = useMutation<AxiosResponse<ExpenseResponse>, AxiosError<ApiErrors>, ExpenseInput>(
    {
      mutationFn,
      onError: () =>
        AlertStore.show(id ? t('alerts.edit-row.error') : t('alerts.new-row.error'), 'error'),
      onSuccess: () => {
        queryClient.invalidateQueries(endpoints.expenses.listExpenses.url)
        router.push(routes.admin.expenses.index)
        AlertStore.show(id ? t('alerts.edit-row.success') : t('alerts.new-row.success'), 'success')
      },
    },
  )

  async function onSubmit(data: ExpenseInput, { setFieldError }: FormikHelpers<ExpenseInput>) {
    try {
      if (data.documentId == '') {
        data.documentId = null
      }
      if (data.approvedById == '') {
        data.approvedById = null
      }
      mutation.mutateAsync(data)
    } catch (error) {
      if (isAxiosError(error)) {
        const { response } = error as AxiosError<ApiErrors>
        response?.data.message.map(({ property, constraints }) => {
          setFieldError(property, t(matchValidator(constraints)))
        })
      }
    }
  }

  return (
    <GenericForm
      onSubmit={onSubmit}
      initialValues={initialValues}
      validationSchema={validationSchema}>
      <Box sx={{ marginTop: '5%', height: '62.6vh' }}>
        <Typography variant="h5" component="h2" sx={{ marginBottom: 2, textAlign: 'center' }}>
          {id ? t('headings.edit') : t('headings.add')}
        </Typography>
        <Grid container spacing={2} sx={{ width: 600, margin: '0 auto' }}>
          <Grid item xs={6}>
            <ExpenseTypeSelect />
          </Grid>
          <Grid item xs={6}>
            <ExpenseStatusSelect />
          </Grid>
          <Grid item xs={6}>
            <FormTextField type="number" name="amount" label="expenses:fields.amount" />
          </Grid>
          <Grid item xs={6}>
            <CurrencySelect />
          </Grid>
          <Grid item xs={6}>
            <VaultSelect />
          </Grid>
          <Grid item xs={6}>
            <DocumentSelect />
          </Grid>
          <Grid item xs={12}>
            <FormTextField
              type="string"
              name="description"
              label="expenses:fields.description"
              multiline
              rows={5}
            />
          </Grid>
          <Grid item xs={id ? 10 : 12}>
            <PersonSelect name="approvedById" namespace="expenses" />
          </Grid>
          {id && (
            <Grid item xs={2}>
              <DeletedCheckbox />
            </Grid>
          )}

          <Grid item xs={6}>
            <SubmitButton fullWidth label={id ? 'expenses:btns.save' : 'expenses:btns.submit'} />
          </Grid>
          <Grid item xs={6}>
            <LinkButton
              fullWidth
              variant="contained"
              color="primary"
              href={routes.admin.expenses.index}>
              {t('btns.cancel')}
            </LinkButton>
          </Grid>
        </Grid>
      </Box>
    </GenericForm>
  )
}
Example #26
Source File: IrregularityForm.tsx    From frontend with MIT License 4 votes vote down vote up
export default function IrregularityForm({ campaign, person }: Props) {
  const { t } = useTranslation('irregularity')
  const classes = useStyles()

  const formRef = useRef<FormikProps<IrregularityFormData>>(null)

  const [fail, setFail] = useState(false)
  const [success, setSuccess] = useState(false)
  const [files, setFiles] = useState<File[]>([])
  const [activeStep, setActiveStep] = useState<Steps>(Steps.GREETING)
  const [failedStep, setFailedStep] = useState<Steps>(Steps.NONE)

  const steps: StepType[] = [
    {
      component: <Greeting />,
    },
    {
      component: <Contacts />,
    },
    {
      component: <Info files={files} setFiles={setFiles} />,
    },
  ]

  const isStepFailed = (step: Steps | number): boolean => {
    return step === failedStep
  }

  const mutation = useMutation<
    AxiosResponse<IrregularityResponse>,
    AxiosError<ApiErrors>,
    IrregularityInput
  >({
    mutationFn: createIrregularity,
  })

  const fileUploadMutation = useMutation<
    AxiosResponse<IrregularityUploadImage[]>,
    AxiosError<ApiErrors>,
    UploadIrregularityFiles
  >({
    mutationFn: uploadIrregularityFiles(),
  })

  const handleBack = () => {
    setActiveStep((prevActiveStep) => prevActiveStep - 1)
  }

  const handleSubmit = async (
    values: IrregularityFormData,
    actions: FormikHelpers<IrregularityFormData>,
  ) => {
    if (isLastStep(activeStep, steps)) {
      const errors = await actions.validateForm(values)
      const hasErrors = !!Object.keys(errors).length
      if (hasErrors) {
        setFailedStep(Steps.INFO)
        return
      }
      setActiveStep((prevActiveStep) => prevActiveStep + 1)
      setFailedStep(Steps.NONE)
      try {
        const data: IrregularityInput = {
          campaignId: values.info.campaignId,
          description: values.info.description,
          notifierType: values.info.notifierType,
          reason: values.info.reason,
          status: values.status,
          person: {
            firstName: values.person.firstName,
            lastName: values.person.lastName,
            email: values.person.email,
            phone: values.person.phone,
          },
        }
        const response = await mutation.mutateAsync(data)
        await fileUploadMutation.mutateAsync({
          files,
          irregularityId: response.data.id,
        })
        actions.resetForm()
        setSuccess(true)
      } catch (error) {
        console.error(error)
        setFail(true)
        if (isAxiosError(error)) {
          const { response } = error as AxiosError<ApiErrors>
          response?.data.message.map(({ property, constraints }) => {
            actions.setFieldError(property, t(matchValidator(constraints)))
          })
        }
      }

      return
    }

    actions.setTouched({})
    actions.setSubmitting(false)

    initialValues.info.campaignId = campaign.id
    initialValues.person.firstName = person?.firstName || ''
    initialValues.person.lastName = person?.lastName || ''
    initialValues.person.email = person?.email || ''
    initialValues.person.phone = person?.phone || ''

    await stepsHandler({ actions, activeStep, setActiveStep, setFailedStep })
  }

  if (success) {
    return <Success />
  }

  if (fail) {
    return <Fail setFail={setFail} setActiveStep={setActiveStep} />
  }

  return (
    <>
      <GenericForm<IrregularityFormData>
        onSubmit={handleSubmit}
        initialValues={initialValues}
        validationSchema={validationSchema[activeStep]}
        innerRef={formRef}>
        <Stepper
          alternativeLabel
          activeStep={activeStep}
          className={classes.stepper}
          connector={<ColorlibConnector />}>
          {steps.map((step, index) => (
            <Step key={index}>
              <StepLabel error={isStepFailed(index)} StepIconComponent={StepIcon} />
            </Step>
          ))}
        </Stepper>
        <div className={classes.content}>
          <Grid container spacing={5} justifyContent="center" className={classes.instructions}>
            <Grid container item xs={12}>
              {activeStep < steps.length && steps[activeStep].component}
            </Grid>
            <Grid container item spacing={3}>
              <Actions
                activeStep={activeStep}
                disableBack={activeStep === 0}
                onBack={handleBack}
                loading={mutation.isLoading}
                campaign={campaign}
                nextLabel={isLastStep(activeStep, steps) ? 'cta.submit' : 'cta.next'}
                backLabel={isFirstStep(activeStep, steps) ? 'cta.back-to-campaign' : 'cta.back'}
              />
            </Grid>
          </Grid>
        </div>
      </GenericForm>
      {activeStep === Steps.GREETING && <Remark text={t('steps.greeting.remark')} />}
      {activeStep === Steps.CONTACTS && <Remark text={t('steps.contacts.remark')} />}
    </>
  )
}
Example #27
Source File: Steps.tsx    From frontend with MIT License 4 votes vote down vote up
export default function DonationStepper() {
  const { t } = useTranslation('one-time-donation')
  const router = useRouter()
  const success = router.query.success === 'true' ? true : false
  initialValues.amount = (router.query.price as string) || ''
  const slug = String(router.query.slug)
  const { data, isLoading } = useViewCampaign(slug)
  if (!data || !data.campaign) return <NotFoundPage />
  const { campaign } = data
  const mutation = useDonationSession()

  const donate = React.useCallback(
    async (amount?: number, priceId?: string) => {
      const { data } = await mutation.mutateAsync({
        mode: 'payment',
        amount,
        priceId,
        campaignId: campaign.id,
        successUrl: `${baseUrl}${routes.campaigns.oneTimeDonation(campaign.slug)}?success=true`,
        cancelUrl: `${baseUrl}${routes.campaigns.oneTimeDonation(campaign.slug)}?success=false`,
      })
      if (data.session.url) {
        window.location.href = data.session.url
      }
    },
    [mutation],
  )

  const onSubmit = async (
    values: OneTimeDonation,
    { setFieldError, resetForm }: FormikHelpers<OneTimeDonation>,
  ) => {
    try {
      const data = {
        currency: 'BGN',
        priceId: values.amount !== 'other' ? values.amount : undefined,
        amount:
          values.amount === 'other'
            ? Math.round((values.otherAmount + Number.EPSILON) * 100)
            : undefined,
      }
      await donate(data.amount, data.priceId)
      resetForm()
    } catch (error) {
      if (isAxiosError(error)) {
        const { response } = error as AxiosError<ApiErrors>
        response?.data.message.map(({ property, constraints }) => {
          setFieldError(property, t(matchValidator(constraints)))
        })
      }
    }
  }
  const steps: StepType[] = [
    {
      label: 'First Step',
      component: <FirstStep />,
      validate: validateFirst,
    },
    {
      label: 'Second Step',
      component: <SecondStep />,
      validate: validateSecond,
    },
    {
      label: 'Third Step',
      component: <ThirdStep />,
      validate: validateThird,
    },
    {
      label: 'Last Step',
      component: success ? <Success /> : <Fail />,
      validate: null,
    },
  ]
  const [step, setStep] = React.useState(0)
  return (
    <StepsContext.Provider value={{ step, setStep, campaign }}>
      {isLoading ? (
        <CircularProgress color="primary" />
      ) : (
        <FormikStepper onSubmit={onSubmit} initialValues={initialValues}>
          {steps.map(({ label, component, validate }) => (
            <FormikStep key={label} validationSchema={validate}>
              {component}
            </FormikStep>
          ))}
        </FormikStepper>
      )}
    </StepsContext.Provider>
  )
}
Example #28
Source File: EntityForm.tsx    From firecms with MIT License 4 votes vote down vote up
/**
 * This is the form used internally by the CMS
 * @param status
 * @param path
 * @param schemaOrResolver
 * @param entity
 * @param onEntitySave
 * @param onDiscard
 * @param onModified
 * @param onValuesChanged
 * @constructor
 * @category Components
 */
export function EntityForm<M>({
                                  status,
                                  path,
                                  schemaOrResolver,
                                  entity,
                                  onEntitySave,
                                  onDiscard,
                                  onModified,
                                  onValuesChanged
                              }: EntityFormProps<M>) {

    const classes = useStyles();
    const dataSource = useDataSource();

    /**
     * Base values are the ones this view is initialized from, we use them to
     * compare them with underlying changes in the datasource
     */
    const entityId = status === "existing" ? entity?.id : undefined;
    const initialResolvedSchema: ResolvedEntitySchema<M> = useMemo(() => computeSchema({
        schemaOrResolver,
        path,
        entityId
    }), [path, entityId]);

    const baseDataSourceValues: Partial<EntityValues<M>> = useMemo(() => {
        const properties = initialResolvedSchema.properties;
        if ((status === "existing" || status === "copy") && entity) {
            return entity.values ?? initWithProperties(properties, initialResolvedSchema.defaultValues);
        } else if (status === "new") {
            return initWithProperties(properties, initialResolvedSchema.defaultValues);
        } else {
            console.error({ status, entity });
            throw new Error("Form has not been initialised with the correct parameters");
        }
    }, [status, initialResolvedSchema, entity]);

    const formRef = React.useRef<HTMLDivElement>(null);

    const [customId, setCustomId] = React.useState<string | undefined>(undefined);
    const [customIdError, setCustomIdError] = React.useState<boolean>(false);
    const [savingError, setSavingError] = React.useState<any>();

    const initialValuesRef = React.useRef<EntityValues<M>>(entity?.values ?? baseDataSourceValues as EntityValues<M>);
    const initialValues = initialValuesRef.current;

    const [internalValue, setInternalValue] = useState<EntityValues<M> | undefined>(initialValues);

    const schema: ResolvedEntitySchema<M> = useMemo(() => computeSchema({
        schemaOrResolver,
        path,
        entityId,
        values: internalValue,
        previousValues: initialValues
    }), [schemaOrResolver, path, entityId, internalValue]);

    const mustSetCustomId: boolean = (status === "new" || status === "copy") && (!!schema.customId && schema.customId !== "optional");

    const underlyingChanges: Partial<EntityValues<M>> = useMemo(() => {
        if (initialValues && status === "existing") {
            return Object.keys(schema.properties)
                .map((key) => {
                    const initialValue = (initialValues as any)[key];
                    const latestValue = (baseDataSourceValues as any)[key];
                    if (!isEqual(initialValue, latestValue)) {
                        return { [key]: latestValue };
                    }
                    return {};
                })
                .reduce((a, b) => ({ ...a, ...b }), {}) as Partial<EntityValues<M>>;
        } else {
            return {};
        }
    }, [initialValues, baseDataSourceValues]);

    const saveValues = useCallback((values: EntityValues<M>, formikActions: FormikHelpers<EntityValues<M>>) => {

        if (mustSetCustomId && !customId) {
            console.error("Missing custom Id");
            setCustomIdError(true);
            formikActions.setSubmitting(false);
            return;
        }

        setSavingError(null);
        setCustomIdError(false);

        let savedEntityId: string | undefined;
        if (status === "existing") {
            if (!entity?.id) throw Error("Form misconfiguration when saving, no id for existing entity");
            savedEntityId = entity.id;
        } else if (status === "new" || status === "copy") {
            if (schema.customId) {
                if (schema.customId !== "optional" && !customId) {
                    throw Error("Form misconfiguration when saving, customId should be set");
                }
                savedEntityId = customId;
            }
        } else {
            throw Error("New FormType added, check EntityForm");
        }

        if (onEntitySave)
            onEntitySave({
                schema: schema as EntitySchema,
                path,
                entityId: savedEntityId,
                values,
                previousValues: entity?.values
            })
                .then(_ => {
                    initialValuesRef.current = values;
                    formikActions.setTouched({});
                })
                .catch(e => {
                    console.error(e);
                    setSavingError(e);
                })
                .finally(() => {
                    formikActions.setSubmitting(false);
                });

    }, [status, path, schema, entity, onEntitySave, mustSetCustomId, customId]);


    const uniqueFieldValidator: CustomFieldValidator = useCallback(({
                                                                        name,
                                                                        value,
                                                                        property
                                                                    }) => dataSource.checkUniqueField(path, name, value, property, entityId),
        [dataSource, path, entityId]);

    const validationSchema = useMemo(() => getYupEntitySchema(
        schema.properties,
        uniqueFieldValidator), [schema.properties]);


    return (
        <Formik
            initialValues={initialValues}
            onSubmit={saveValues}
            validationSchema={validationSchema}
            validate={(values) => console.debug("Validating", values)}
            onReset={() => onDiscard && onDiscard()}
        >
            {({
                  values,
                  touched,
                  setFieldValue,
                  handleSubmit,
                  isSubmitting,
                  dirty
              }) => {

                return <FormInternal baseDataSourceValues={baseDataSourceValues}
                                     values={values} onModified={onModified}
                                     setInternalValue={setInternalValue}
                                     onValuesChanged={onValuesChanged}
                                     underlyingChanges={underlyingChanges}
                                     entityId={entityId}
                                     entity={entity}
                                     touched={touched}
                                     setFieldValue={setFieldValue}
                                     schema={schema}
                                     isSubmitting={isSubmitting}
                                     classes={classes}
                                     formRef={formRef}
                                     status={status}
                                     setCustomId={setCustomId}
                                     customIdError={customIdError}
                                     handleSubmit={handleSubmit}
                                     savingError={savingError}/>;
            }}
        </Formik>
    );
}
Example #29
Source File: SetPasswordForm.tsx    From bada-frame with GNU General Public License v3.0 4 votes vote down vote up
function SetPasswordForm(props: Props) {
    const [loading, setLoading] = useState(false);
    const onSubmit = async (
        values: formValues,
        { setFieldError }: FormikHelpers<formValues>
    ) => {
        setLoading(true);
        try {
            const { passphrase, confirm } = values;
            if (passphrase === confirm) {
                await props.callback(passphrase, setFieldError);
            } else {
                setFieldError('confirm', constants.PASSPHRASE_MATCH_ERROR);
            }
        } catch (e) {
            setFieldError('confirm', `${constants.UNKNOWN_ERROR} ${e.message}`);
        } finally {
            setLoading(false);
        }
    };
    return (
        <Container>
            <Card style={{ maxWidth: '540px', padding: '20px' }}>
                <Card.Body>
                    <div
                        className="text-center"
                        style={{ marginBottom: '40px' }}>
                        <p>{constants.ENTER_ENC_PASSPHRASE}</p>
                        {constants.PASSPHRASE_DISCLAIMER()}
                    </div>
                    <Formik<formValues>
                        initialValues={{ passphrase: '', confirm: '' }}
                        validationSchema={Yup.object().shape({
                            passphrase: Yup.string().required(
                                constants.REQUIRED
                            ),
                            confirm: Yup.string().required(constants.REQUIRED),
                        })}
                        validateOnChange={false}
                        validateOnBlur={false}
                        onSubmit={onSubmit}>
                        {({
                            values,
                            touched,
                            errors,
                            handleChange,
                            handleSubmit,
                        }) => (
                            <Form noValidate onSubmit={handleSubmit}>
                                <Form.Group>
                                    <Form.Control
                                        type="password"
                                        placeholder={constants.PASSPHRASE_HINT}
                                        value={values.passphrase}
                                        onChange={handleChange('passphrase')}
                                        isInvalid={Boolean(
                                            touched.passphrase &&
                                                errors.passphrase
                                        )}
                                        autoFocus
                                        disabled={loading}
                                    />
                                    <Form.Control.Feedback type="invalid">
                                        {errors.passphrase}
                                    </Form.Control.Feedback>
                                </Form.Group>
                                <Form.Group>
                                    <Form.Control
                                        type="password"
                                        placeholder={
                                            constants.RE_ENTER_PASSPHRASE
                                        }
                                        value={values.confirm}
                                        onChange={handleChange('confirm')}
                                        isInvalid={Boolean(
                                            touched.confirm && errors.confirm
                                        )}
                                        disabled={loading}
                                    />
                                    <Form.Control.Feedback type="invalid">
                                        {errors.confirm}
                                    </Form.Control.Feedback>
                                </Form.Group>
                                <SubmitButton
                                    buttonText={props.buttonText}
                                    loading={loading}
                                />
                            </Form>
                        )}
                    </Formik>
                    {props.back && (
                        <div
                            className="text-center"
                            style={{ marginTop: '20px' }}>
                            <Button variant="link" onClick={props.back}>
                                {constants.GO_BACK}
                            </Button>
                        </div>
                    )}
                </Card.Body>
            </Card>
        </Container>
    );
}