formik#useFormik JavaScript Examples

The following examples show how to use formik#useFormik. 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: FormContext.js    From ecommerce with MIT License 6 votes vote down vote up
FormProvider = ({ initialValues, validationSchema, onSubmit, children }) => {
  const { handleChange, handleBlur, values, touched, errors, submitForm } = useFormik({
    initialValues,
    validationSchema,
    onSubmit,
    validateOnChange: true,
    validateOnMount: true,
  });

  const defaultContext = useMemo(
    () => ({
      handleChange,
      handleBlur,
      values,
      touched,
      errors,
      submitForm,
    }),
    [handleChange, handleBlur, values, touched, errors, submitForm]
  );

  return <FormContext.Provider value={defaultContext}>{children}</FormContext.Provider>;
}
Example #2
Source File: AppTasks.js    From course-manager with MIT License 6 votes vote down vote up
export default function AppTasks() {
  const formik = useFormik({
    initialValues: {
      checked: [TASKS[2]]
    },
    onSubmit: (values) => {
      console.log(values);
    }
  });

  const { values, handleSubmit } = formik;

  return (
    <Card>
      <CardHeader title="Tasks" />
      <Box sx={{ px: 3, py: 1 }}>
        <FormikProvider value={formik}>
          <Form autoComplete="off" noValidate onSubmit={handleSubmit}>
            {TASKS.map((task) => (
              <TaskItem
                key={task}
                task={task}
                formik={formik}
                checked={values.checked.includes(task)}
              />
            ))}
          </Form>
        </FormikProvider>
      </Box>
    </Card>
  );
}
Example #3
Source File: about-us-title-edit-form.js    From horondi_admin with MIT License 5 votes vote down vote up
AboutUsTitleEditForm = ({ businessPage }) => {
  const dispatch = useDispatch();

  const [updateTitle, { loading }] = useMutation(updateBusinessText, {
    onCompleted: () => {
      dispatch(showSuccessSnackbar(SUCCESS_UPDATE_STATUS));
    },
    onError: () => {
      dispatch(showErrorSnackbar(ERROR_BOUNDARY_STATUS));
    }
  });

  const onSubmit = (onSubmitValues) => {
    const updatedBusinessPage = getBusinessPageWithUpdatedTitle(
      businessPage,
      onSubmitValues
    );
    updateTitle({
      variables: setVariablesForUpdatingPage(updatedBusinessPage)
    });
  };

  const { values, errors, touched, handleChange, handleBlur, submitForm } =
    useFormik({
      initialValues: getInitialValuesForTitleEditing(businessPage),
      validationSchema: titleEditValidationSchema,
      onSubmit
    });

  const inputOptions = {
    errors,
    touched,
    handleChange,
    handleBlur,
    values,
    inputs: [titleEditInput]
  };

  if (loading) {
    return <LoadingBar />;
  }

  return (
    <div>
      <EditingButtonsPanel
        pathBack={pathToAboutUs}
        submitForm={submitForm}
        values={values}
        errors={errors}
      />
      <form>
        {languages.map((lang) => (
          <LanguagePanel lang={lang} inputOptions={inputOptions} key={lang} />
        ))}
      </form>
    </div>
  );
}
Example #4
Source File: use-comment-validation.spec.js    From horondi_client_fe with MIT License 5 votes vote down vote up
useFormik.mockImplementation(() => formik);
Example #5
Source File: LoginCard.js    From bunk-manager-mern with MIT License 5 votes vote down vote up
LoginCard = (props) => {
  const location = useLocation();
  let { from } = location.state || { from: { pathname: "/" } };
  //styles
  const classes = useStyles(props);
  //formik hook
  const formik = useFormik({
    initialValues: {
      email: "",
      password: "",
    },
    validationSchema: loginSchema,
    onSubmit: (values) => {
      props.loggingUser(values, from);
    },
  });

  return (
    <React.Fragment>
      <Typography color="primary" className={classes.loginHeader} variant="h5">
        Sign In
      </Typography>
      <form
        autoComplete="off"
        className={classes.form}
        onSubmit={formik.handleSubmit}
      >
        {props.error ? <div>{props.error.msg}</div> : null}
        <input
          id="login-email"
          label="Email"
          value={formik.values.email}
          onChange={formik.handleChange}
          error={
            formik.touched.email && Boolean(formik.errors.email).toString()
          }
          variant="outlined"
          name="email"
          placeholder="Username or Email"
          type="text"
          className={classes.input}
        />
        {formik.errors.email ? <div>{formik.errors.email}</div> : null}
        <input
          name="password"
          placeholder="Password"
          type="password"
          className={classes.input}
          id="login-password"
          value={formik.values.password}
          onChange={formik.handleChange}
          error={
            formik.touched.password &&
            Boolean(formik.errors.password).toString()
          }
        />
        {formik.errors.password ? <div>{formik.errors.password}</div> : null}
        <Button
          type="submit"
          className={classes.button}
          color="secondary"
          variant="contained"
        >
          {props.auth.isLoading ? (
            <CircularProgress color="primary" />
          ) : (
            "Sign In"
          )}
        </Button>
      </form>
    </React.Fragment>
  );
}
Example #6
Source File: index.js    From website with MIT License 5 votes vote down vote up
WishesFilterBy = ({ onLatLngUpdated, items, currentRefinement, refine }) => {
  const validationSchema = Yup.object().shape({
    postalCode: Yup.string().matches(/\d{6}/, 'Invalid postal code'),
  });

  const formik = useFormik({
    initialValues: {
      postalCode: '',
    },
    validationSchema: validationSchema,
    onSubmit: (values) => {
      handleSubmitPostalCode(values);
    },
  });

  const handleSubmitPostalCode = async (values) => {
    try {
      const { postalCode } = values;
      if (postalCode.trim().length > 0) {
        const postalCodeArray = [postalCode];
        const locations = await getLocations(postalCodeArray);
        if (locations.length > 0) {
          const latLng = `${locations[0].latitude},${locations[0].longitude}`;
          onLatLngUpdated(latLng);
        } else {
          onLatLngUpdated('');
        }
      } else {
        onLatLngUpdated('');
      }
    } catch (error) {
      console.error(error.message);
    }
  };

  return (
    <div>
      <BlackText style={{ marginBottom: '10px' }} size="large">
        Filter By
      </BlackText>
      <Separator />

      <Stack>
        {items.map((item, index) => {
          return (
            <Checkbox
              label={item.label + ' (' + item.count + ') '}
              value={item.value}
              checked={item.isRefined}
              key={item.value}
              onChange={() => {
                refine(item.value);
              }}
            />
          );
        })}

        <form onSubmit={formik.handleSubmit}>
          <Stack>
            <InputField
              placeholder="postal code"
              label="Nearest - Furthest"
              error={formik.touched.postalCode && formik.errors.postalCode ? formik.errors.postalCode : ''}
              {...formik.getFieldProps('postalCode')}
            />
            <Button onClick={formik.handleSubmit}>Go</Button>
          </Stack>
        </form>
      </Stack>
    </div>
  );
}
Example #7
Source File: questions-answers-form.js    From horondi_admin with MIT License 4 votes vote down vote up
FormQNA = ({ id, editMode }) => {
  const dispatch = useDispatch();
  const { loading, questionsAnswers } = useSelector(({ QuestionsAnswers }) => ({
    loading: QuestionsAnswers.loading,
    questionsAnswers: QuestionsAnswers.currentPage
  }));

  const classes = useStyles();
  const common = useCommonStyles();
  const {
    labels: { questionaAnswersLabel },
    languages
  } = config;

  const { pathToBusinessPages } = config.routes;

  const {
    createQuestionsAnswers,
    uaSetAnswer,
    enSetAnswer,
    uaSetQuestion,
    enSetQuestion,
    uaAnswer,
    enAnswer,
    enQuestion,
    uaQuestion
  } = useQuestionsAnswersHandlers();

  useEffect(() => {
    id && dispatch(getQuestionsAnswersById(id));
  }, [dispatch, id]);

  useEffect(() => {
    const isEditingReady = !!questionsAnswers;

    uaSetQuestion(uaSetQuestionsHandler(isEditingReady, questionsAnswers));
    uaSetAnswer(uaSetAnswersHandler(isEditingReady, questionsAnswers));
    enSetQuestion(enSetQuestionsHandler(isEditingReady, questionsAnswers));
    enSetAnswer(enSetAnswersHandler(isEditingReady, questionsAnswers));
  }, [
    editMode,
    questionsAnswers,
    uaSetAnswer,
    uaSetQuestion,
    enSetAnswer,
    enSetQuestion
  ]);

  const {
    values,
    errors,
    touched,
    handleSubmit,
    handleBlur,
    handleChange,
    setFieldValue
  } = useFormik({
    initialValues: {
      uaQuestion,
      enQuestion,
      uaAnswer,
      enAnswer
    },
    onSubmit: async (data) => {
      const page = createQuestionsAnswers({
        ...data
      });
      questionsAnswersDispatchHandler(
        editMode,
        dispatch,
        updateQuestionsAnswers,
        addQuestionsAnswers,
        { id, page },
        page
      );
    }
  });

  const changed = useChangedValuesChecker(values, errors);
  const unblock = useUnsavedChangesHandler(values);

  useMemo(() => {
    values.uaQuestion = uaQuestion;
    values.enQuestion = enQuestion;
    values.uaAnswer = uaAnswer;
    values.enAnswer = enAnswer;
  }, [uaQuestion, enQuestion, uaAnswer, enAnswer]);

  if (loading) {
    return <LoadingBar />;
  }

  const inputOptions = {
    errors,
    touched,
    handleChange,
    handleBlur,
    values,
    inputs: questionaAnswersLabel,
    setFieldValue
  };

  const eventPreventHandler = (e) => {
    e.preventDefault();
  };

  return (
    <div className={classes.container}>
      <div className={classes.buttonContainer}>
        <Grid container spacing={2} className={classes.fixedButtons}>
          <Grid item className={classes.button}>
            <BackButton pathBack={pathToBusinessPages} />
          </Grid>
          <Grid item className={classes.button}>
            <SaveButton
              id='save'
              type='submit'
              title='Зберегти'
              data-cy='save-btn'
              onClickHandler={handleSubmit}
              unblockFunction={unblock}
              values={{}}
              errors={errors}
              {...(id ? { disabled: !changed } : {})}
            />
          </Grid>
        </Grid>
      </div>
      <div className={common.adminHeader}>
        <Typography
          variant='h1'
          className={common.materialTitle}
          data-cy='add-header'
        >
          {config.titles.questionsAnswersTitles.addQuestionsAnswersTitle}
        </Typography>
      </div>

      <form onSubmit={(e) => eventPreventHandler(e)}>
        {languages.map((lang) => (
          <LanguagePanel lang={lang} inputOptions={inputOptions} key={lang} />
        ))}
      </form>
    </div>
  );
}
Example #8
Source File: gift-certificate.js    From horondi_client_fe with MIT License 4 votes vote down vote up
GiftCertificate = () => {
  const { t } = useTranslation();
  const styles = useStyles();
  const appStyles = useAppStyles();

  const [getPaymentCheckoutForCertificate] = useLazyQuery(getPaymentCheckoutForCertificates, {
    onCompleted: (data) => {
      const { paymentUrl, paymentToken, certificatesOrderId } =
        data.getPaymentCheckoutForCertificates;
      setToLocalStorage(orderDataToLS.certificatesOrderId, certificatesOrderId);
      window.open(`${process.env.REACT_APP_ROOT_PATH}${pathToCertificateThanks}/${paymentToken}`);
      window.open(paymentUrl);
    }
  });

  const [generateCertificates] = useMutation(generateCertificate, {
    onCompleted: (data) => {
      const { certificates, certificatesPrice } = data.generateCertificate;
      getPaymentCheckoutForCertificate({
        variables: {
          data: {
            currency: getCurrentCurrency(currency),
            amount: String(certificatesPrice),
            certificates
          }
        }
      });
    }
  });

  const initialValues = {
    email: ''
  };

  const { userData, currency } = useSelector(({ User, Currency }) => ({
    userData: User.userData,
    currency: Currency.currency
  }));

  const CHECKBOXES_STATE = [
    { value: 500, checked: false, count: INITIAL_CERTIFICATE_COUNT },
    { value: 1000, checked: true, count: INITIAL_CERTIFICATE_COUNT },
    { value: 1500, checked: false, count: INITIAL_CERTIFICATE_COUNT }
  ];

  const [checkboxesArr, setCheckboxesArr] = useState(CHECKBOXES_STATE);

  const { errors, values, touched, handleChange, handleSubmit, handleBlur, resetForm } = useFormik({
    validationSchema,
    initialValues,
    onSubmit: () => {
      const newCertificates = findCheckedCertificates(checkboxesArr);
      generateCertificates({
        variables: {
          newCertificates,
          email: values.email
        }
      });
    }
  });

  useEffect(() => {
    if (userData) {
      resetForm({
        values: {
          email: userData.email
        }
      });
    }
  }, [userData, resetForm]);

  const handleCheckboxChange = (value, checkboxIndex) => {
    setCheckboxesArr(
      checkboxesArr.map((checkbox, index) =>
        index === checkboxIndex ? { ...checkbox, checked: value } : checkbox
      )
    );
  };

  const handleCountChange = (count, index) => {
    setCheckboxesArr(
      checkboxesArr.map((checkbox, key) => (key === index ? { ...checkbox, count } : checkbox))
    );
  };

  const findCheckedCertificates = (certificates) =>
    certificates
      .filter((certificate) => certificate.checked === true)
      .map(({ checked, ...keepAtrs }) => keepAtrs);

  const checkboxContent = checkboxesArr.map((checkbox, index) => (
    <CertificateCheckbox
      handleAllCheckboxesChange={handleCheckboxChange}
      handleAllCountChange={handleCountChange}
      checked={checkbox.checked}
      index={index}
      key={checkbox.value}
      value={checkbox.value}
    />
  ));

  const certificateText = (index) => t(`certificate.certificateRules.${index}`);

  const certificateRulesContent = certificateRules.map((_, index) => (
    <React.Fragment key={index}>
      {`${index + 1}. ${certificateText(index)}`}
      <br />
    </React.Fragment>
  ));

  return (
    <div className={appStyles.rootApp}>
      <div className={appStyles.containerApp}>
        <h1 className={styles.pageTitle}>{t('certificate.giftCertificate')}</h1>
        <h2 className={styles.chooseCertificate}>{t('certificate.chooseCertificate')}</h2>
        <div className={styles.checkboxWrapper}>{checkboxContent}</div>
        <div className={styles.lowerWrapper}>
          <div>{certificateRulesContent}</div>
          <form onSubmit={handleSubmit}>
            <div className={styles.formWrapper}>
              <TextField
                id='email'
                data-testid='email'
                fullWidth
                label={t('checkout.checkoutTextFields.email')}
                variant={TEXT_FIELD_VARIANT.OUTLINED}
                className={styles.textField}
                onBlur={handleBlur}
                onChange={handleChange}
                value={values.email}
                color={MATERIAL_UI_COLOR.PRIMARY}
                name='email'
                error={touched.email && Boolean(t(errors.email))}
                helperText={touched.email && t(errors.email)}
              />
              <Button
                data-testid='button'
                className={styles.purchaseButton}
                fullWidth
                type='submit'
              >
                {t('buttons.buyButton')}
              </Button>
            </div>
          </form>
        </div>
      </div>
    </div>
  );
}
Example #9
Source File: ContactForm.js    From gatsby-theme-try-ghost with MIT License 4 votes vote down vote up
ContactForm = ({ topics, serviceConfig }) => {
    const text = get(useLang())
    const validate = useValidate(text)

    const encodeFormData = (data) => {
        if (serviceConfig.contentType === `application/json`) {
            return JSON.stringify(data)
        }
        if (serviceConfig.contentType === `application/x-www-form-urlencoded`) {
            return Object.keys(data)
                .map(key => encodeURIComponent(key) + `=` + encodeURIComponent(data[key]))
                .join(`&`)
        }
        return data
    }
    const formik = useFormik({
        initialValues: {
            name: ``,
            email: ``,
            subject: topics.length > 0 ? `topic` : ``,
            message: ``,
            'form-name': ``,
        },
        validate,
        onSubmit: async (values, actions) => {
            actions.setSubmitting(false)

            values.source_url = window.location.href
            values.subject = topics[values.subject]
            if (typeof values[`form-name`] === `string` && values[`form-name`].length === 0) {
                values[`form-name`] = `gatsby-theme-ghost-contact`
            } else { //early return if robot
                actions.resetForm()
                actions.setStatus({ success: text(`MESSAGE_SENT`) })
                return
            }

            const postURL = (serviceConfig.url || `/`)

            // reset and show message as post can be slow!
            actions.resetForm()
            actions.setStatus({ success: text(`ONE_SECOND`) })

            fetch(postURL, {
                method: `POST`,
                headers: { 'Content-Type': serviceConfig.contentType },
                body: encodeFormData(values),
            }).then(() => {
                actions.resetForm()
                actions.setStatus({ success: text(`MESSAGE_SENT`) })
                //remove message after 10 seconds
                window.setTimeout(() => actions.setStatus({ success: `` }), 10000)
            }).catch((error) => {
                actions.resetForm()
                actions.setStatus({ success: `${text(`SENDING_FAILED`)}: ${error}.` })
                //remove message after 10 seconds
                window.setTimeout(() => actions.setStatus({ success: `` }), 10000)
            })
        },
    })

    return (
        <>
            <Span id="response">
                <div>{printError(formik.touched, formik.errors)}</div>
            </Span>
            <Form
                name="gatsby-theme-ghost-contact"
                method="post"
                action=""
                onSubmit={formik.handleSubmit}
                data-netlify="true"
                data-netlify-honeypot="bot-field">
                <Input
                    id="name"
                    name="name"
                    type="text"
                    onChange={formik.handleChange}
                    onBlur={formik.handleBlur}
                    value={formik.values.name}
                    placeholder={text(`FULL_NAME`)}
                />
                <Input
                    id="email"
                    name="email"
                    type="email"
                    onChange={formik.handleChange}
                    onBlur={formik.handleBlur}
                    value={formik.values.email}
                    placeholder={text(`EMAIL_ADDRESS`)}
                />
                { topics.length > 0 &&
                    <Select
                        id="subject"
                        name="subject"
                        onChange={formik.handleChange}
                        onBlur={formik.handleBlur}
                        value={formik.values.subject}>
                        <option value="topic" hidden>{text(`PLEASE_SELECT`)}</option>
                        { topics.map((topic, i) => (
                            <option num={i} value={i} key={`option-${i}`} >{topic}</option>
                        ))}
                    </Select>
                }
                <Textarea
                    id="message"
                    name="message"
                    onChange={formik.handleChange}
                    onBlur={formik.handleBlur}
                    value={formik.values.message}
                    placeholder={text(`YOUR_MESSAGE`)}
                    rows="5"
                />
                <Robot
                    type="hidden"
                    name="form-name"
                    onChange={formik.handleChange}
                    value={formik.values[`form-name`]}
                />
                <Button id="submit" type="submit" value="Submit">{text(`SUBMIT`)}</Button>
                <Response id="responsemsg">{formik.status && formik.status.success}</Response>
            </Form>
        </>
    )
}
Example #10
Source File: demo.js    From react-use-opentok with MIT License 4 votes vote down vote up
Demo = () => {
  const [opentokProps, opentokMethods] = useOpenTok();
  const [credentials, setCredentials] =
    typeof window !== 'undefined'
      ? useLocalStorage('credentials', initialCredentials)
      : [initialCredentials];

  const {
    connectionId,
    isSessionConnected,

    session,
    connections,
    streams,
    subscribers,
    publisher,
  } = opentokProps;

  const {
    initSessionAndConnect,
    disconnectSession,
    publish,
    unpublish,
    subscribe,
    unsubscribe,
    sendSignal,
  } = opentokMethods;

  const credentialsFormik = useFormik({
    initialValues: {
      ...JSON.parse(credentials),
    },
    onSubmit: async (values, { setSubmitting }) => {
      const { apiKey, sessionId, token } = values;
      setCredentials(
        JSON.stringify({
          ...values,
        })
      );

      await initSessionAndConnect({
        apiKey,
        sessionId,
        token,
      });

      setSubmitting(false);
    },
  });

  const signalFormik = useFormik({
    initialValues: {
      type: '',
      data: '',
    },
    onSubmit: (values, { setSubmitting, resetForm }) => {
      if (values.data.length === 0) {
        console.warn('signal data is empty');
        return;
      }

      sendSignal({
        ...values,
      });

      setTimeout(() => {
        resetForm();
        setSubmitting(false);
      }, 400);
    },
  });

  // Listener of `signal`
  // References https://tokbox.com/developer/sdks/js/reference/SignalEvent.html
  const handleSignal = useCallback(e => {
    console.log('handleSignal', e);
  }, []);

  const handleSessionDisconnected = useCallback(e => {
    console.log('handle session disconnected', e);
  }, []);

  useEffect(() => {
    if (!isSessionConnected) {
      return;
    }
    session.on('signal', handleSignal);
    session.once('sessionDisconnected', handleSessionDisconnected);
    return () => {
      session.off('signal', handleSignal);
    };
  }, [handleSignal, handleSessionDisconnected, isSessionConnected, session]);

  const streamGroups =
    streams &&
    streams.reduce((groups, stream) => {
      const { connection } = stream;
      groups[connection.connectionId] = groups[connection.connectionId] || [];
      groups[connection.connectionId].push(stream);
      return groups;
    }, {});

  if (typeof window === 'undefined') return null;

  return (
    <>
      <div
        sx={{
          display: 'flex',
          mb: 3,
        }}
      >
        {/* Left Side */}
        <div
          sx={{
            flex: 2,
          }}
        >
          <div
            sx={{
              position: 'relative',
              minHeight: 480,
              backgroundColor: 'black',
              width: `100%`,
            }}
          >
            <div
              id="subscriber"
              sx={{
                position: 'absolute',
                left: 0,
                top: 0,
                right: 0,
                bottom: 0,
                zIndex: 2,
              }}
            ></div>
            <div
              id="camera"
              sx={{
                position: 'absolute',
                width: 240,
                height: 180,
                right: 10,
                bottom: 10,
                zIndex: 3,
              }}
            ></div>
            <div
              id="screen"
              sx={{
                position: 'absolute',
                width: 240,
                height: 180,
                right: 10,
                top: 10,
                zIndex: 3,
              }}
            ></div>
          </div>
          <div>
            {isSessionConnected ? (
              <>
                <div
                  sx={{
                    mt: 3,
                  }}
                >
                  <Button variant="primary" onClick={disconnectSession}>
                    Disconnect to Session
                  </Button>

                  {!publisher.camera ? (
                    <Button
                      variant="primary"
                      onClick={() => {
                        publish({
                          name: 'camera',
                          element: 'camera',
                        });
                      }}
                    >
                      Publish Camera Stream
                    </Button>
                  ) : (
                    <Button
                      variant="secondary"
                      onClick={() => unpublish({ name: 'camera' })}
                    >
                      Stop Publish
                    </Button>
                  )}

                  {!publisher.screen ? (
                    <Button
                      variant="primary"
                      onClick={() =>
                        publish({
                          name: 'screen',
                          element: 'screen',
                          options: {
                            ...defaultOpenTokOptions,
                            videoSource: 'screen',
                          },
                        })
                      }
                    >
                      Start Share Screen (Desktop)
                    </Button>
                  ) : (
                    <Button
                      variant="secondary"
                      onClick={() => unpublish({ name: 'screen' })}
                    >
                      Stop Share Screen (Desktop)
                    </Button>
                  )}
                </div>

                <Box as="form" onSubmit={signalFormik.handleSubmit}>
                  <Label htmlFor="type" my={3}>
                    Signal
                  </Label>
                  <Input
                    name="type"
                    placeholder="Type"
                    onChange={signalFormik.handleChange}
                    value={signalFormik.values.type}
                    mb={3}
                  />
                  <Textarea
                    name="data"
                    placeholder="Data"
                    onChange={signalFormik.handleChange}
                    value={signalFormik.values.data}
                    rows="6"
                    mb={3}
                  />
                  <Button
                    variant="secondary"
                    type="submit"
                    sx={{
                      display: 'block',
                      marginLeft: 'auto',
                    }}
                    disabled={
                      !signalFormik.values.data.length ||
                      signalFormik.isSubmitting
                    }
                  >
                    Send Signal
                  </Button>
                </Box>
              </>
            ) : (
              <Box as="form" onSubmit={credentialsFormik.handleSubmit}>
                <Label htmlFor="apiKey" mt={3} mb={1}>
                  API Key
                </Label>
                <Input
                  name="apiKey"
                  mb={3}
                  onChange={credentialsFormik.handleChange}
                  value={credentialsFormik.values.apiKey}
                />
                <Label htmlFor="sessionId" mb={1}>
                  Session ID
                </Label>
                <Input
                  name="sessionId"
                  mb={3}
                  onChange={credentialsFormik.handleChange}
                  value={credentialsFormik.values.sessionId}
                />
                <Label htmlFor="apiKey" mb={1}>
                  Token
                </Label>
                <Input
                  name="token"
                  mb={3}
                  onChange={credentialsFormik.handleChange}
                  value={credentialsFormik.values.token}
                />
                <Button
                  variant="secondary"
                  type="submit"
                  disabled={credentialsFormik.isSubmitting}
                  sx={{
                    display: 'block',
                    marginLeft: 'auto',
                  }}
                >
                  Connect to Session
                </Button>
              </Box>
            )}
            <ConsoleFeed />
          </div>
        </div>

        {/* Right Side */}
        <div
          sx={{
            flex: 1,
            px: 3,
          }}
        >
          <div sx={{ pt: 3 }}>Connections</div>
          <ul sx={{ pl: '1rem', mt: 2 }}>
            {connections.map(c => (
              <li key={c.connectionId}>
                {c.connectionId}{' '}
                {c.connectionId === connectionId && (
                  <Badge variant="outline" ml={1}>
                    You
                  </Badge>
                )}
              </li>
            ))}
          </ul>
          <div sx={{ pt: 3 }}>Streams</div>
          <ul sx={{ pl: '1rem', mt: 2 }}>
            {Object.entries(streamGroups).map(([groupId, streams]) => (
              <li key={groupId}>
                Connection ID: {groupId.split('-')[0]}{' '}
                {groupId === connectionId && (
                  <Badge variant="outline" ml={1}>
                    You
                  </Badge>
                )}
                <ul sx={{ pl: '1rem', py: 2 }}>
                  {streams.map(stream => {
                    const { streamId, connection } = stream;
                    return (
                      <li key={streamId}>
                        {connection.connectionId === connectionId ? (
                          `Stream ID: ${streamId.split('-')[0]} (${
                            stream.videoType
                          })`
                        ) : (
                          <>
                            {`Stream ID: ${streamId.split('-')[0]}`}{' '}
                            {subscribers.some(
                              subscriber => subscriber.streamId === streamId
                            ) ? (
                              <Button
                                variant="secondary"
                                sx={{
                                  p: 1,
                                  fontSize: 0,
                                  border: '1px solid',
                                  mx: 1,
                                }}
                                onClick={() => unsubscribe({ stream })}
                              >
                                STOP
                              </Button>
                            ) : (
                              <Button
                                variant="primary"
                                sx={{
                                  p: 1,
                                  fontSize: 0,
                                  border: '1px solid',
                                  mx: 1,
                                }}
                                onClick={() =>
                                  subscribe({ stream, element: 'subscriber' })
                                }
                              >
                                Watch
                              </Button>
                            )}
                          </>
                        )}
                      </li>
                    );
                  })}
                </ul>
              </li>
            ))}
          </ul>
        </div>
      </div>
    </>
  );
}
Example #11
Source File: LtiConfigForm.jsx    From frontend-app-course-authoring with GNU Affero General Public License v3.0 4 votes vote down vote up
function LtiConfigForm({ onSubmit, intl, formRef }) {
  const dispatch = useDispatch();

  const { selectedAppId, piiConfig } = useSelector((state) => state.discussions);
  const appConfig = useModel('appConfigs', selectedAppId);
  const app = useModel('apps', selectedAppId);
  const providerName = intl.formatMessage(appMessages[`appName-${app?.id}`]);
  const ltiAppConfig = {
    consumerKey: appConfig?.consumerKey || '',
    consumerSecret: appConfig?.consumerSecret || '',
    launchUrl: appConfig?.launchUrl || '',
    piiShareUsername: piiConfig.piiSharing ? piiConfig.piiShareUsername : undefined,
    piiShareEmail: piiConfig.piiSharing ? piiConfig.piiShareEmail : undefined,
  };
  const user = getAuthenticatedUser();
  const { externalLinks } = app;
  const {
    handleSubmit, handleChange, handleBlur, values, touched, errors,
  } = useFormik({
    initialValues: ltiAppConfig,
    validationSchema: Yup.object().shape({
      consumerKey: Yup.string().required(intl.formatMessage(messages.consumerKeyRequired)),
      consumerSecret: Yup.string().required(intl.formatMessage(messages.consumerSecretRequired)),
      launchUrl: Yup.string().required(intl.formatMessage(messages.launchUrlRequired)),
      piiShareUsername: Yup.bool(),
      piiShareEmail: Yup.bool(),
    }),
    onSubmit,
  });
  const isInvalidConsumerKey = Boolean(touched.consumerKey && errors.consumerKey);
  const isInvalidConsumerSecret = Boolean(touched.consumerSecret && errors.consumerSecret);
  const isInvalidLaunchUrl = Boolean(touched.launchUrl && errors.launchUrl);
  const showLTIConfig = user.administrator;
  const enablePIISharing = false;
  const supportEmails = {
    Yellowdig: '[email protected]',
    'Ed Discussion': '[email protected]',
    InScribe: '[email protected]',
    Piazza: '[email protected]',
  };

  useEffect(() => {
    dispatch(updateValidationStatus({ hasError: Object.keys(errors).length > 0 }));
  }, [errors]);

  return (
    <Card className="mb-5 p-5" data-testid="ltiConfigForm">
      <Form ref={formRef} onSubmit={handleSubmit}>
        <h3 className="mb-3">{providerName}</h3>
        <p>
          <FormattedMessage
            {...messages.staffOnlyConfigInfo}
            values={{
              providerName,
              supportEmail: supportEmails[providerName] ? (
                <MailtoLink to={supportEmails[providerName]}>{supportEmails[providerName]}</MailtoLink>
              ) : (
                'support'
              ),
            }}
          />
        </p>
        <p>
          <FormattedMessage
            {...messages.staffOnlyConfigGuide}
            values={{
              providerName,
              supportEmail: supportEmails[providerName] ? (
                <MailtoLink to={supportEmails[providerName]}>{supportEmails[providerName]}</MailtoLink>
              ) : (
                'support'
              ),
            }}
          />
        </p>
        {(showLTIConfig && piiConfig.piiSharing) && (
          <>
            <p>{intl.formatMessage(messages.formInstructions)}</p>
            <Form.Group
              controlId="consumerKey"
              isInvalid={isInvalidConsumerKey}
              className="mb-4"
              data-testid="ltiConfigFields"
            >
              <Form.Control
                floatingLabel={intl.formatMessage(messages.consumerKey)}
                onChange={handleChange}
                onBlur={handleBlur}
                value={values.consumerKey}
              />
              {isInvalidConsumerKey && (
                <Form.Control.Feedback type="invalid" hasIcon={false}>
                  <span className="x-small">{errors.consumerKey}</span>
                </Form.Control.Feedback>
              )}
            </Form.Group>
            <Form.Group
              controlId="consumerSecret"
              isInvalid={isInvalidConsumerSecret}
              className="mb-4"
            >
              <Form.Control
                floatingLabel={intl.formatMessage(messages.consumerSecret)}
                onChange={handleChange}
                onBlur={handleBlur}
                value={values.consumerSecret}
              />
              {isInvalidConsumerSecret && (
                <Form.Control.Feedback type="invalid" hasIcon={false}>
                  <span className="x-small">{errors.consumerSecret}</span>
                </Form.Control.Feedback>
              )}
            </Form.Group>
            <Form.Group controlId="launchUrl" isInvalid={isInvalidLaunchUrl}>
              <Form.Control
                floatingLabel={intl.formatMessage(messages.launchUrl)}
                onChange={handleChange}
                onBlur={handleBlur}
                value={values.launchUrl}
              />
              {isInvalidLaunchUrl && (
                <Form.Control.Feedback type="invalid" hasIcon={false}>
                  <span className="x-small">{errors.launchUrl}</span>
                </Form.Control.Feedback>
              )}
            </Form.Group>
          </>
        )}
        {(enablePIISharing) && (
          <div data-testid="piiSharingFields">
            <Form.Text className="my-2">{intl.formatMessage(messages.piiSharing)}</Form.Text>
            <Form.Group controlId="piiSharing">
              <Form.Check
                type="checkbox"
                name="piiShareUsername"
                onChange={handleChange}
                onBlur={handleBlur}
                checked={values.piiShareUsername}
                label={intl.formatMessage(messages.piiShareUsername)}
              />
              <Form.Check
                type="checkbox"
                name="piiShareEmail"
                onChange={handleChange}
                onBlur={handleBlur}
                checked={values.piiShareEmail}
                label={intl.formatMessage(messages.piiShareEmail)}
              />
            </Form.Group>
          </div>
        )}
      </Form>
      <AppExternalLinks
        externalLinks={externalLinks}
        providerName={providerName}
        customClasses="small text-muted"
      />
    </Card>
  );
}
Example #12
Source File: checkout-form.js    From muffinsplantshop with BSD Zero Clause License 4 votes vote down vote up
BillingForm = ({ setValues, shippingValues, setSection, sameAsShipping, setSameAsShipping, billingValues }) => {
    const validationSchema = baseSchema.shape({
        country: Yup.string().required("Required")
    })
    const { handleSubmit, handleChange, values, errors } = useFormik({
        initialValues: {
            firstName: billingValues ? billingValues.firstName : "",
            lastName: billingValues ? billingValues.lastName : "",
            addressOne: billingValues ? billingValues.addressOne : "",
            addressTwo: billingValues ? billingValues.addressTwo : "",
            municipality: billingValues ? billingValues.municipality : "",
            provinceTerritory: billingValues ? billingValues.provinceTerritory : "",
            postalCode: billingValues ? billingValues.postalCode : "",
            country: billingValues ? billingValues.country : ""
        },
        validationSchema,
        onSubmit(values) {
            setValues(values);
            setSection('payment');
        }
    });

    return (
        <div>
            <div className={styles.checkoutForm__sameAsBilling}>
                <input
                    checked={sameAsShipping}
                    id="sameAsShipping"
                    name="sameAsShipping"
                    onChange={(e) => setSameAsShipping(e.target.checked)}
                    type="checkbox" />
                <label htmlFor="sameAsShipping">My billing address is the same as my shipping address</label>
            </div>

            {sameAsShipping ?
                (<>
                    <Details values={shippingValues} section="billing" />
                    <div style={{ padding: `0 1rem` }}>
                        <button
                            className={styles.checkoutForm__submitButton}
                            data-testid="submit-billing-button"
                            onClick={() => setSection('payment')}
                            type="button">
                            Continue to payment
                        </button>
                    </div>
                </>) :
                (<form
                    className={styles.checkoutForm__form}
                    data-testid="billing-form"
                    onSubmit={handleSubmit}>
                    <div className={styles.checkoutForm__field}>
                        <label htmlFor="firstName">First Name<span className="required">*</span></label>
                        <input
                            id="firstName"
                            name="firstName"
                            onChange={handleChange}
                            type="text"
                            value={values.firstName} />
                        <span className={styles.checkoutForm__error}>{errors.firstName ? errors.firstName : null}</span>
                    </div>
                    <div className={styles.checkoutForm__field}>
                        <label htmlFor="lastName">Last Name<span className="required">*</span></label>
                        <input
                            id="lastName"
                            name="lastName"
                            onChange={handleChange}
                            type="text"
                            value={values.lastName} />
                        <span className={styles.checkoutForm__error}>{errors.lastName ? errors.lastName : null}</span>
                    </div>
                    <div className={styles.checkoutForm__field}>
                        <label htmlFor="country">Country<span className="required">*</span></label>
                        <input
                            id="country"
                            name="country"
                            onChange={handleChange}
                            type="text"
                            value={values.country} />
                        <span className={styles.checkoutForm__error}>{errors.addressOne ? errors.addressOne : null}</span>
                    </div>
                    <div className={styles.checkoutForm__field}>
                        <label htmlFor="addressOne">Address Line 1<span className="required">*</span></label>
                        <input
                            id="addressOne"
                            name="addressOne"
                            onChange={handleChange}
                            type="text"
                            value={values.addressOne} />
                        <span className={styles.checkoutForm__error}>{errors.addressOne ? errors.addressOne : null}</span>
                    </div>
                    <div className={styles.checkoutForm__field}>
                        <label htmlFor="addressTwo">Address Line 2</label>
                        <input
                            id="addressTwo"
                            name="addressTwo"
                            onChange={handleChange}
                            type="text"
                            value={values.addressTwo} />
                        <span className={styles.checkoutForm__error}>{errors.addressTwo ? errors.addressTwo : null}</span>
                    </div>
                    <div className={styles.checkoutForm__field}>
                        <label htmlFor="municipality">Municipality<span className="required">*</span></label>
                        <input
                            id="municipality"
                            name="municipality"
                            onChange={handleChange}
                            type="text"
                            value={values.municipality} />
                        <span className={styles.checkoutForm__error}>{errors.municipality ? errors.municipality : null}</span>
                    </div>
                    <div className={styles.checkoutForm__field}>
                        <label htmlFor="provinceTerritory">Province/Territory<span className="required">*</span></label>
                        <select
                            value={values.provinceTerritory}
                            id="provinceTerritory"
                            name="provinceTerritory"
                            onChange={handleChange}>
                            <option value="">Select</option>
                            <option value="AB">Alberta</option>
                            <option value="BC">British Columbia</option>
                            <option value="MB">Manitoba</option>
                            <option value="NB">New Brunswick</option>
                            <option value="NL">Newfoundland  and Labrador</option>
                            <option value="NS">Nova Scotia</option>
                            <option value="NT">Northwest Territories</option>
                            <option value="NU">Nunavut</option>
                            <option value="ON">Ontario</option>
                            <option value="PE">Prince Edward Island</option>
                            <option value="QC">Quebec</option>
                            <option value="SK">Saskatchewan</option>
                            <option value="YT">Yukon</option>
                        </select>
                        <span className={styles.checkoutForm__error}>{errors.provinceTerritory ? errors.provinceTerritory : null}</span>
                    </div>
                    <div className={styles.checkoutForm__field}>
                        <label htmlFor="postalCode">Postal Code<span className="required">*</span></label>
                        <input
                            id="postalCode"
                            name="postalCode"
                            onChange={handleChange}
                            type="text"
                            value={values.postalCode} />
                        <span className={styles.checkoutForm__error}>{errors.postalCode ? errors.postalCode : null}</span>
                    </div>
                    <button
                        className={styles.checkoutForm__submitButton}
                        data-testid="submit-billing-button"
                        type="submit">continue to payment</button>
                </form>)
            }
        </div >
    )
}
Example #13
Source File: RuleForm.jsx    From acid-tabs-extension with MIT License 4 votes vote down vote up
RuleForm = (props) => {
  const { groupRules, saveGroupRules, handleUpdate, handleCollapseGroups, showConfirm, handleConfirm } = props;
  const [isDirty, setIsDirty] = useState(false);
  const [isBulkMode, setIsBulkMode] = useState(false);
  const [bulkValue, setBulkValue] = useState(groupRules.map(ruleToText).join('\n'));
  const [newestRule, setNewestRule] = useState(null);
  const [isCollapsed, setIsCollapsed] = useState(false);
  const [showBottomRow, setShowBottomRow] = useState(false);
  const [movedRule, setMovedRule] = useState({});
  const formik = useFormik({
    initialValues: {
      groupRules
    },
    onSubmit: (values) => {
      saveGroupRules(values.groupRules)
    },
  });

  const removeRule = (index) => {
    formik.values.groupRules.splice(index, 1)
    formik.setFieldValue(formik.values.groupRules);
    setIsDirty(true);
    saveGroupRules(formik.values.groupRules)
  }

  const updateRuleOrder = (index, change) => {
    const otherIndex = index + change;
    setMovedRule({ [index]: change > 0 ? 'down' : 'up' })
    setTimeout(() => {
      formik.values.groupRules[index].key = otherIndex;
      formik.values.groupRules[otherIndex].key = index;
      formik.setFieldValue(formik.values.groupRules.sort((a, b) => a.key - b.key));
      setIsDirty(true)
      setMovedRule({})
      saveGroupRules(formik.values.groupRules)
    }, 100)
  }

  const getNewColor = () => {
    const colorCounts = Object.keys(COLORS).reduce((curr, prev) => ({ ...curr, [prev]: 0 }), {})
    formik.values.groupRules
      .filter(rule => rule.color && Number.isInteger(colorCounts[rule.color]))
      .forEach(rule => { colorCounts[rule.color] = colorCounts[rule.color] + 1 });
    const colorsSortedByUse = Object.entries(colorCounts)
      .sort((a, b) => a[1] - b[1])
      .map(c => c[0]);
    return colorsSortedByUse[0];
  }

  const addNewRule = () => {
    const newRule = {
      name: '',
      pattern: '',
      key: formik.values.groupRules.length,
      color: getNewColor(),
    }
    formik.setFieldValue(formik.values.groupRules.push(newRule));
    setNewestRule(formik.values.groupRules.length)
  }

  const allowUp = index => index > 0;
  const allowDown = index => index < (formik.values.groupRules && formik.values.groupRules.length - 1);
  const allValid = formik.values.groupRules.every(rule => rule.name.length > 0 && rule.pattern.length > 0)
  const changed = formik.dirty || isDirty;
  
  const textToRules = (rawText) => {
    const lines = rawText.split('\n');
    const rules = lines.map((line, i) => lineToRule(line, i)).filter(r => !!r)
    return rules;
  }
  const lineToRule = (text, key) => {
    const fields = text.split(',').map(f => f.replace('   ', '\n').trim())
    if (text.trim().length === 0) return null;
    if (fields.length < 2 || fields.length > 3 || fields.slice(0, 2).some(f => f.length === 0)) {
      return { error: 'Invalid format' }
    }
    const color = fields.length > 2 && Object.keys(COLORS).includes(fields[2]) ? fields[2] : getNewColor();
    return { key, name: fields[0], pattern: fields[1], color }
  }

  const handleCollapse = (state) => {
    setIsCollapsed(state)
    handleCollapseGroups(state)
  }

  const updateCollapsed = async() => {
    const newIsCollapsed = await isAnyAcidTabGroupCollapsed();
    setIsCollapsed(newIsCollapsed);
  }

  const toggleCollapseListener = async (command) => {
    if (command === 'toggle-collapse') {
      setTimeout(updateCollapsed, 100);
    }
  };

  useEffect(() => {
    if (allValid) {
      saveGroupRules(formik.values.groupRules)
      setBulkValue(formik.values.groupRules.map(ruleToText).join('\n'))
    }
  }, [formik.values.groupRules])

  useEffect(() => {
    updateCollapsed();
    setTimeout(() => setShowBottomRow(true), 10)
    chrome.commands.onCommand.addListener(toggleCollapseListener);
    return () => chrome.commands.onCommand.removeListener(toggleCollapseListener);
  }, [])

  if (showConfirm) {
    return <TabDemo onConfirm={handleConfirm} />;
  }

  if (isBulkMode) {
    const parsedRules = textToRules(bulkValue);
    const isBulkValid = parsedRules.every(r => !r.error)
    const confirmBulk = (rules) => {
      if (!isBulkValid) return;
      saveGroupRules(parsedRules, true)
      setIsBulkMode(false)
    }
    return (
      <Wrapper style={{ marginTop: '1rem', padding: '0 1rem' }}>
        <TextField
          fullWidth
          key={`bulkValue`}
          name={`bulkValue`}
          label='Raw Text Rules (per line: "name, pattern")'
          value={bulkValue}
          error={!isBulkValid}
          multiline
          placeholder='name, pattern'
          onChange={(e) => setBulkValue(e.target.value)}
        />
        <Row style={{ flex: 10, marginTop: '1rem', marginBottom: '1rem' }} alignItems='flex-end' justifyContent='center' alwaysShow>
          <Button disabled={!isBulkValid} variant='contained' color="primary" onClick={confirmBulk}>
            <DoneIcon style={{ paddingRight: '0.5rem' }} />
            Confirm
          </Button>
        </Row>
      </Wrapper>
    )
  }

  const getMove = (i) => {
    if (movedRule[i]) {
      return movedRule[i];
    }

    
    if (movedRule[i-1] == 'down') {
      if (i === 1) return 'fade';
      return 'up'
    }
    if (movedRule[i+1] == 'up') {
      if (i === 0) return 'fade';
      return 'down'
    }
  }

  const indirectlyMoved = i => getMove(i) && !movedRule[i];

  const shouldShowLabel = (i) => i === 0;

  return (
    <Wrapper style={{}}>
      <br />
      <form onSubmit={formik.handleSubmit}>
        {/* <Icon style={{ position: 'absolute' }}><ArrowBackIcon /></Icon> */}
        {formik.values.groupRules.length === 0 && (
          <FillColumn style={{ justifyContent: 'center', fontSize: '1.1rem' }}>
            <FilterListIcon style={{ fontSize: '2.5rem' }} />
            No rules yet, add one to start!
          </FillColumn>
        )}
        {/* {formik.values.groupRules.length > 0 && (
          <Row className={'special-hide'} key={'null'} alignItems='flex-end' style={{ paddingLeft: '1rem', boxSizing: 'border-box' }}>
            <TextField
              style={{ minWidth: '8rem' }}
              key={`groupRules.${0}.name`}
              name={`groupRules.${0}.name`}
              label={shouldShowLabel(0) ? "Name" : null}
              value
              required
              placeholder='Group Name'
            />
            <TextField
              fullWidth
              key={`groupRules.${0}.pattern`}
              name={`groupRules.${0}.pattern`}
              label={shouldShowLabel(0) ? "URL Pattern (space separated for multiple)" : null}
              required
              multiline
              placeholder='URL Pattern ("google.com")'
            />
            <Select
              key={`groupRules.${0}.color`}
              name={`groupRules.${0}.color`}
              displayEmpty
            >
              {Object.entries(COLORS).map(([colorKey, colorVal]) => (
                <MenuItem value={colorKey}><ColorCircle value={colorVal} /></MenuItem>
              ))}
            </Select>
          </Row>
        )} */}
        {formik.values.groupRules.map((groupRule, i) => (
          <Row className={getMove(i) ? `moving moving--${getMove(i)} ${indirectlyMoved(i) ? 'moving--indirect' : ''}` : ''} key={groupRule.key || '0'} alignItems='flex-end' style={{ paddingLeft: '1rem', boxSizing: 'border-box' }}>
            <TextField
              style={{ minWidth: '8rem' }}
              key={`groupRules.${i}.name`}
              name={`groupRules.${i}.name`}
              label={shouldShowLabel(i) ? "Name" : null}
              value={groupRule.name}
              error={formik.dirty && groupRule.name.length === 0}
              autoFocus={i === newestRule - 1}
              required
              placeholder='Group Name'
              onChange={formik.handleChange}
            />
            <TextField
              fullWidth
              key={`groupRules.${i}.pattern`}
              name={`groupRules.${i}.pattern`}
              label={shouldShowLabel(i) ? "URL Pattern (space separated for multiple)" : null}
              value={groupRule.pattern}
              error={formik.dirty && groupRule.pattern.length === 0}
              required
              multiline
              placeholder='URL Pattern ("google.com")'
              onChange={formik.handleChange}
            />
            <Select
              key={`groupRules.${i}.color`}
              name={`groupRules.${i}.color`}
              value={groupRule.color}
              onChange={formik.handleChange}
              displayEmpty
              renderValue={(val) => (
                <ColorCircle value={COLORS[groupRule.color]} displayMode />
              )}
            >
              {Object.entries(COLORS).map(([colorKey, colorVal]) => (
                <MenuItem value={colorKey}><ColorCircle value={colorVal} /></MenuItem>
              ))}
            </Select>
            <PostCol>
              <ArrowUpwardIcon className={`icon ${!allowUp(i) ? 'disabled' : ''}`} onClick={() => allowUp(i) && updateRuleOrder(i, -1)} />
              <ArrowDownwardIcon className={`icon ${!allowDown(i) ? 'disabled' : ''}`} onClick={() => allowDown(i) && updateRuleOrder(i, 1)} />
              <DeleteIcon className='icon icon--delete' onClick={() => removeRule(i)} />
            </PostCol>
          </Row>
        ))}

        <Row className={`bottom-row ${showBottomRow ? 'bottom-row--show' : ''}`}  style={{ flex: 10, marginBottom: '1rem', marginTop: '1rem' }} alignItems='flex-end' justifyContent='space-between' alwaysShow>
          <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'flex-start' }}>
            <Tooltip title="Hotkey: Alt+Shift+C">
              <Button onClick={() => handleCollapse(!isCollapsed)} style={{ marginLeft: '1rem', minWidth: '8rem' }}>
                {isCollapsed ? (
                  <>
                    <ClearAllIcon style={{ paddingRight: '1.25rem' }} />
                    <div>Expand</div>
                  </>
                ) : (
                  <>
                    <SortIcon style={{ paddingRight: '0.5rem' }} />
                    <div>Collapse</div>
                  </>
                )}
              </Button>
            </Tooltip>
            <Button onClick={() => setIsBulkMode(true)} style={{ marginLeft: '0.5rem' }}>
              <EditIcon style={{ paddingRight: '0.75rem' }} />
              <div>Bulk Edit</div>
            </Button>
          </div>
          <Fab color="primary" aria-label="add" style={{ marginRight: '7rem' }} onClick={addNewRule}>
            <AddIcon />
          </Fab>
        </Row>
      </form>
    </Wrapper>
  );
}
Example #14
Source File: profile-page.js    From horondi_client_fe with MIT License 4 votes vote down vote up
ProfilePage = () => {
  const [userImageUrl, setUserImageUrl] = useState(null);
  const [upload, setUpload] = useState(null);
  const [deleteAvatar, setDeleteAvatar] = useState(false);
  const [shouldValidate, setShouldValidate] = useState(false);
  const { t, i18n } = useTranslation();
  const language = i18n.language === 'ua' ? 0 : 1;

  const classes = useStyles();
  const appStyles = useAppStyles();
  const dispatch = useDispatch();

  const {
    userData,
    userLoading,
    confirmationEmailSent,
    userRecovered,
    confirmationLoading,
    recoveryLoading
  } = useSelector(({ User }) => ({
    userData: User.userData,
    userLoading: User.userLoading,
    confirmationEmailSent: User.confirmationEmailSent,
    userRecovered: User.userRecovered,
    confirmationLoading: User.confirmationLoading,
    recoveryLoading: User.recoveryLoading
  }));
  const handleSaveUser = ({ firstName, lastName, email, phoneNumber, ...address }) => {
    if (phoneNumber === null) {
      phoneNumber = '';
    }
    const user = { firstName, lastName, email, phoneNumber, address };
    Object.keys(address).forEach((key) => {
      if (address[key] === null) {
        address[key] = '';
      }
    });

    dispatch(updateUser({ user, id: userData._id, upload, deleteAvatar }));
    setShouldValidate(false);
  };

  const { errors, values, touched, handleBlur, resetForm, handleSubmit, handleChange } = useFormik({
    initialValues,
    onSubmit: handleSaveUser,
    validationSchema,
    validateOnChange: shouldValidate,
    validateOnBlur: shouldValidate
  });

  const handleConfirmation = () => {
    dispatch(sendConfirmationEmail({ email: userData.email, language }));
  };

  const handlePasswordChange = () => {
    dispatch(recoverUser({ email: userData.email, language }));
  };

  useEffect(() => {
    if (userData) {
      const { firstName, lastName, email, phoneNumber, address } = userData;
      resetForm({
        values: {
          firstName,
          lastName,
          email,
          phoneNumber,
          ...address
        }
      });
    }
    if (userData.images && userData.images.thumbnail) {
      setUserImageUrl(IMG_URL + userData.images.thumbnail);
    }
  }, [userData, resetForm]);

  const getTextFields = (textFields) =>
    Object.keys(textFields).map((name) => (
      <TextField
        key={name}
        type='text'
        name={name}
        variant={TEXT_FIELD_VARIANT.OUTLINED}
        value={values[name]?.startsWith('+380') ? values[name].slice(4) : values[name]}
        InputProps={
          name === 'phoneNumber'
            ? {
              maxLength: 9,
              startAdornment: <InputAdornment position='start'>+380</InputAdornment>
            }
            : {}
        }
        label={t(`profilePage.labels.${name}`)}
        fullWidth
        color={MATERIAL_UI_COLOR.PRIMARY}
        onChange={handleChange}
        error={touched[name] && !!errors[name]}
        helperText={t(errors[name])}
        className={handleClassName(classes.dataInput, classes.nameInputs, name)}
      />
    ));

  const emailSent = (titleText) => (
    <div className={classes.emailSent} data-testid='emailSent'>
      <OpenedLetterIcon className={classes.openedLetterIcon} />
      <h3 className={classes.formTitle}>{titleText}</h3>
      <p>{t('profilePage.checkEmailText')}</p>
    </div>
  );

  const passwordChange = () =>
    userRecovered ? (
      emailSent(t('profilePage.passwordChange.heading'))
    ) : (
      <>
        <h3 className={classes.formTitle}>{t('profilePage.passwordChange.heading')}</h3>
        <span className={classes.userActionsText}>{t('profilePage.passwordChange.text')}</span>
        <Button
          className={`${classes.button} ${classes.userActionsButton}`}
          onClick={handlePasswordChange}
          data-testid='passwordChangeBtn'
        >
          {t('profilePage.passwordChange.btnTitle')}
        </Button>
      </>
    );

  const confirmEmail = () =>
    confirmationEmailSent ? (
      emailSent(t('profilePage.emailConfirm.heading'))
    ) : (
      <>
        <h3 className={classes.formTitle}>{t('profilePage.emailConfirm.heading')}</h3>
        <TextField
          data-cy='confirmEmail'
          id='confirmEmail'
          label={t('profilePage.labels.confirmEmail')}
          className={classes.userActionsInput}
          fullWidth
          variant={TEXT_FIELD_VARIANT.OUTLINED}
          color={MATERIAL_UI_COLOR.PRIMARY}
          value={values.email}
          name='confirmEmail'
          onChange={handleChange}
          onBlur={handleBlur}
          error={Boolean(touched.confirmEmail && t(errors.confirmEmail))}
          helperText={touched.confirmEmail && t(errors.confirmEmail)}
        />
        <span className={classes.userActionsText}>
          {!confirmationEmailSent && t('profilePage.emailConfirm.text')}
        </span>
        <Button
          className={`${classes.button} ${classes.userActionsButton}`}
          onClick={handleConfirmation}
          data-testid='emailConfirmBtn'
        >
          {t('profilePage.emailConfirm.btnTitle')}
        </Button>
      </>
    );

  return (
    <div className={appStyles.rootApp}>
      <div className={appStyles.containerApp}>
        <div className={classes.profileTitleInfo}>
          <h2 className={classes.profileTitle}>{t('profilePage.titles.mainTitle')}</h2>
          <div className={classes.titleLine} />
        </div>
        <div className={classes.profile}>
          <div>
            {userLoading ? (
              <div className={classes.userForm}>
                <Loader gridColumn='span 3' />
              </div>
            ) : (
              <div className={classes.userFormControl}>
                <form onSubmit={handleSubmit} className={classes.userForm} data-testid='userForm'>
                  <Avatar
                    userImageUrl={userImageUrl}
                    setUserImageUrl={setUserImageUrl}
                    setUpload={setUpload}
                    setDeleteAvatar={setDeleteAvatar}
                    t={t}
                  />
                  <h3 className={classes.formTitle}>{t('profilePage.titles.contactTitle')}</h3>
                  {getTextFields(PROFILE_USER_CONTACT_DATA)}
                  <h3 className={classes.formTitle}>{t('profilePage.titles.addressTitle')}</h3>
                  {getTextFields(PROFILE_USER_ADDRESS_DATA)}
                  <Button
                    fullWidth
                    className={`${classes.button} ${classes.saveBtn}`}
                    type='submit'
                    onClick={() => setShouldValidate(true)}
                    data-testid='submitBtn'
                  >
                    {t('profilePage.labels.saveBtnTitle')}
                  </Button>
                </form>
              </div>
            )}
          </div>
          <div className={classes.userActions}>
            <div className={classes.newPassword}>
              {recoveryLoading ? <Loader /> : passwordChange()}
            </div>
            {!userData.confirmed && (
              <div className={classes.confirmUser}>
                {confirmationLoading ? <Loader /> : confirmEmail()}
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}
Example #15
Source File: user-form.js    From horondi_admin with MIT License 4 votes vote down vote up
UserForm = ({ user, id, edit }) => {
  const styles = useStyles();
  const dispatch = useDispatch();
  const { createUser, setUserImage, setUpload, upload } = useUserHandlers();

  const userValidationSchema = Yup.object().shape({
    userFirstName: Yup.string()
      .min(2, USER_FIRSTNAME_MIN_LENGTH_MESSAGE)
      .max(30, USER_FIRSTNAME_MAX_LENGTH_MESSAGE)
      .required(USER_ERROR_MESSAGE)
      .matches(firstName, USER_FIRSTNAME_MESSAGE),
    userLastName: Yup.string()
      .min(2, USER_LASTNAME_MIN_LENGTH_MESSAGE)
      .max(30, USER_LASTNAME_MAX_LENGTH_MESSAGE)
      .required(USER_ERROR_MESSAGE)
      .matches(lastName, USER_LASTNAME_MESSAGE),
    email: Yup.string()
      .required(USER_EMAIL_MESSAGE)
      .matches(email, USER_INVALID_EMAIL_MESSAGE),
    phoneNumber: Yup.string()
      .required(USER_PHONE_NUMBER_MESSAGE)
      .matches(phoneNumber, USER_INVALID_PHONE_NUMBER_MESSAGE),
    country: Yup.string().matches(uaRegex, USER_INVALID_ADDRESS_MESSAGE),
    region: Yup.string().matches(uaRegex, USER_INVALID_ADDRESS_MESSAGE),
    city: Yup.string().matches(uaRegex, USER_INVALID_ADDRESS_MESSAGE),
    street: Yup.string().matches(uaRegex, USER_INVALID_ADDRESS_MESSAGE),
    house: Yup.string().matches(uaNameCreation, USER_INVALID_ADDRESS_MESSAGE),
    flat: Yup.string().matches(categoryCode, USER_INVALID_ADDRESS_MESSAGE),
    zipcode: Yup.string().matches(postCode, USER_INVALID_ADDRESS_MESSAGE),
    userImage: Yup.string()
  });

  const {
    values,
    handleSubmit,
    handleChange,
    handleBlur,
    touched,
    errors,
    setFieldValue
  } = useFormik({
    validationSchema: userValidationSchema,
    initialValues: getUserInitialValues(user, edit, IMG_URL),

    onSubmit: () => {
      const editedUser = createUser(values);
      const editAndUpload = edit && upload instanceof File;
      if (editAndUpload || edit) {
        userFormOnSubmit(
          editAndUpload,
          dispatch,
          updateUserById,
          {
            id,
            user: editedUser,
            image: upload
          },
          edit,
          {
            id,
            user: editedUser
          }
        );
      }
    }
  });

  const unblock = useUnsavedChangesHandler(values);

  const handleImageLoad = (files) => {
    if (files && files[0]) {
      const reader = new FileReader();
      reader.onload = (data) => {
        setFieldValue('userImage', data.target.result);
        setUserImage(data.target.result);
      };
      reader.readAsDataURL(files[0]);
      setUpload(files[0]);
    }
  };

  const eventPreventHandler = (e) => {
    e.preventDefault();
  };
  return (
    <div>
      <form onSubmit={(e) => eventPreventHandler(e)}>
        <div className={styles.buttonContainer}>
          <Grid container spacing={2} className={styles.fixedButtons}>
            <Grid item className={styles.button}>
              <BackButton
                className={styles.returnButton}
                pathBack={pathToUsers}
              />
            </Grid>
            <Grid item className={styles.button}>
              <SaveButton
                className={styles.saveButton}
                data-cy='save'
                type='submit'
                title={SAVE_TITLE}
                values={values}
                errors={errors}
                onClickHandler={handleSubmit}
                unblockFunction={unblock}
              />
            </Grid>
          </Grid>
        </div>

        <Paper className={styles.colorPaper}>
          <Grid item xs={12}>
            <Paper>
              <span className={styles.userImage}>Фото користувача</span>
              <div className={styles.userImage}>
                <ImageUploadContainer
                  handler={handleImageLoad}
                  src={values.userImage}
                />
              </div>
            </Paper>
          </Grid>
          {Object.keys(labels).map((fieldName) => (
            <React.Fragment key={fieldName}>
              <TextField
                id={fieldName}
                data-cy={fieldName}
                className={styles.textField}
                variant='outlined'
                label={labels[fieldName]}
                value={values[fieldName]}
                onChange={handleChange}
                onBlur={handleBlur}
                error={touched[fieldName] && !!errors[fieldName]}
              />
              {touched[fieldName] && errors[fieldName] && (
                <div className={styles.inputError}>{errors[fieldName]}</div>
              )}
            </React.Fragment>
          ))}
        </Paper>
      </form>
    </div>
  );
}
Example #16
Source File: checkout-form.js    From horondi_client_fe with MIT License 4 votes vote down vote up
CheckoutForm = ({ cartItems, cartOperations, promoCode }) => {
  const { currency } = useContext(CurrencyContext);
  const styles = useStyles();
  const appStyles = useAppStyles();
  const userData = useSelector(({ User }) => User.userData);
  const { t, i18n } = useTranslation();
  const language = i18n.language === 'ua' ? 0 : 1;
  const { clearCart } = cartOperations;
  const dispatch = useDispatch();
  const [deliveryType, setDeliveryType] = useState(
    getFromSessionStorage(SESSION_STORAGE.DELIVERY_TYPE) || deliveryTypes.SELFPICKUP
  );
  const [countryOption, setCountryOption] = useState(countryOptions.WITHIN_UKRAINE);
  const [initialValues, setInitialValues] = useState(stateInitialValues);
  const [pricesFromQuery, setPricesFromQuery] = useState([]);

  const handleCountryOption = (_, newTabValue) => setCountryOption(newTabValue);

  const { discount, categories } = promoCode?.getPromoCodeByCode || {};

  const totalPriceToPay = pricesFromQuery
    .map((item, index) => {
      const canUsePromoCode = categories?.includes(item.category?.code);
      const priceWithPromoCode = calcPriceForCart(item.price, cartItems[index]?.quantity, discount);
      const priceWithoutPromoCode = calcPriceForCart(item.price, cartItems[index]?.quantity);

      return canUsePromoCode ? priceWithPromoCode : priceWithoutPromoCode;
    })
    .reduce((previousValue, currentValue) => previousValue + currentValue, 0);

  const consentLink = (
    <div className={styles.consentMessage}>
      {' '}
      {t('checkout.checkoutAdditionalInfo.consent.0')}
      <Link
        className={styles.consentLink}
        to={pathToUserAgreement}
        target='_blank'
        rel='noreferrer'
      >
        {' '}
        {t('checkout.checkoutAdditionalInfo.consent.1')}{' '}
      </Link>{' '}
      {t('checkout.checkoutAdditionalInfo.consent.2')}
      <Link className={styles.consentLink} to={pathToTerms} target='_blank' rel='noreferrer'>
        {' '}
        {t('checkout.checkoutAdditionalInfo.consent.3')}{' '}
      </Link>
    </div>
  );

  const { values, handleSubmit, handleChange, setFieldValue, touched, errors } = useFormik({
    enableReinitialize: true,
    validationSchema: validationSchema(deliveryType, countryOption, t),
    initialValues,

    onSubmit: (data) => {
      if (data.paymentMethod === checkoutPayMethod.card) {
        dispatch(addPaymentMethod(checkoutPayMethod.card));
        dispatch(
          getFondyData({
            order: orderInputData(data, deliveryType, cartItems, countryOption),
            currency
          })
        );
      } else {
        dispatch(addOrder(orderInputData(data, deliveryType, cartItems, countryOption)));
        dispatch(addPaymentMethod(checkoutPayMethod.cash));
      }
      clearSessionStorage();
      clearCart();
    }
  });

  useEffect(() => {
    setToSessionStorage(SESSION_STORAGE.CHECKOUT_FORM, values);
  }, [values]);

  useEffect(() => {
    if (userData) {
      setInitialValues(updateInitialValues(userData, deliveryType));
    }
  }, [userData, deliveryType]);

  return (
    <div className={appStyles.rootApp}>
      <form onSubmit={handleSubmit} className={appStyles.containerApp}>
        <Grid item className={styles.checkoutFormContainer}>
          <div className={styles.checkoutTitleInfo}>
            <div className={styles.checkoutTitleInfoData}>
              <Link to={pathToCart} className={styles.backBtn}>
                <KeyboardBackspaceIcon color={getThemeColor()} className={styles.backBtnLine} />
              </Link>
            </div>
            <h2 className={styles.checkoutTitle}>{t('checkout.checkoutTitles.checkoutTitle')}</h2>
            <div className={styles.checkoutTitleLine} />
          </div>
          <Grid item className={styles.userInfoContainer}>
            <div>
              <h3 className={styles.title}>{t('checkout.checkoutTitles.contactInfo')}</h3>
              <div className={styles.contactInfoFields}>
                {userContactLabels.map((field) => (
                  <div key={field.name} className={styles.inputData}>
                    <TextField
                      data-testid={field.name}
                      size={TEXT_FIELDS.SMALL}
                      data-cy={field.name}
                      name={field.name}
                      className={styles.textField}
                      variant={TEXT_FIELD_VARIANT.OUTLINED}
                      label={field.label}
                      value={values[field.name]}
                      onChange={handleChange}
                      error={handleError(touched[field.name], errors[field.name])}
                      InputProps={
                        field.name === 'phoneNumber' && {
                          maxLength: 9,
                          startAdornment: <InputAdornment position='start'>+380</InputAdornment>
                        }
                      }
                    />
                    {touched[field.name] && errors[field.name] && (
                      <div data-cy={CY_CODE_ERR} className={styles.error}>
                        {t(errors[field.name])}
                      </div>
                    )}
                  </div>
                ))}
              </div>
            </div>
            <h3 className={styles.deliveryTitle}>{t('checkout.checkoutTitles.delivery')}</h3>
            <Tabs
              className={styles.tabs}
              value={countryOption}
              TabIndicatorProps={{ style: { display: 'none' } }}
              onChange={handleCountryOption}
              variant='fullWidth'
              scrollButtons='auto'
              aria-label='delivery type'
            >
              <Tab
                className={styles.tab}
                label={t('checkout.tabs.withinUkraineDelivery')}
                value={countryOptions.WITHIN_UKRAINE}
              />
              <Tab
                className={styles.tab}
                label={t('checkout.tabs.worldWideDelivery')}
                value={countryOptions.WORLDWIDE}
              />
            </Tabs>
            <Delivery
              deliveryType={deliveryType}
              countryOption={countryOption}
              language={language}
              values={values}
              errors={errors}
              touched={touched}
              handleChange={handleChange}
              setFieldValue={setFieldValue}
              setDeliveryType={setDeliveryType}
            />
            <div>
              <h2 className={styles.title}>{t('checkout.checkoutTitles.payment')}</h2>
              <FormControl
                error={touched.paymentMethod && !!errors.paymentMethod}
                variant={TEXT_FIELD_VARIANT.OUTLINED}
                className={styles.formControl}
              >
                <InputLabel variant={TEXT_FIELD_VARIANT.OUTLINED}>
                  {t('checkout.checkoutTextFields.paymentMethod')}
                </InputLabel>
                <Select
                  data-testid='paymentMetod'
                  label={t('checkout.checkoutTextFields.paymentMethod')}
                  className={styles.paymentSelect}
                  data-cy='paymentMethod'
                  name='paymentMethod'
                  value={values.paymentMethod}
                  onChange={handleChange}
                >
                  {countryOption === countryOptions.WORLDWIDE ? (
                    <MenuItem value={checkoutPayMethod.card}>
                      {t(`checkout.checkoutPayment.${checkoutPayMethod.card}`)}
                    </MenuItem>
                  ) : (
                    Object.values(checkoutPayMethod).map((value) => (
                      <MenuItem key={value} value={value}>
                        {t(`checkout.checkoutPayment.${value}`)}
                      </MenuItem>
                    ))
                  )}
                </Select>
                {touched.paymentMethod && errors.paymentMethod && (
                  <div data-cy={CY_CODE_ERR} className={styles.error}>
                    {t(errors.paymentMethod)}
                  </div>
                )}
              </FormControl>
            </div>
            <div className={styles.contactPaymentInfo}>
              <h2 className={styles.title}>{t('checkout.checkoutTitles.orderComment')}</h2>
              <div>
                <TextField
                  size={TEXT_FIELDS.SMALL}
                  data-cy='userComment'
                  name='userComment'
                  multiline
                  rows={4}
                  className={styles.textAreaField}
                  variant={TEXT_FIELD_VARIANT.OUTLINED}
                  value={values.userComment}
                  onChange={handleChange}
                  error={handleError(touched.userComment, errors.userComment)}
                />
                {touched.userComment && errors.userComment && (
                  <div data-cy={CY_CODE_ERR} className={styles.error}>
                    {t(errors.userComment)}
                  </div>
                )}
              </div>
              <p className={styles.contactInfoAdditional}>
                {t('checkout.checkoutAdditionalInfo.additionalInfo')}
              </p>
            </div>
          </Grid>
          <Grid item className={styles.deliveryContainer}>
            <YourOrder
              checkoutFormBtnValue={checkoutFormBtnValue}
              consentLink={consentLink}
              t={t}
              currency={currency}
              totalPriceToPay={totalPriceToPay}
              values={values}
              language={language}
              styles={styles}
              deliveryType={deliveryType}
              setPricesFromQuery={setPricesFromQuery}
              promoCode={promoCode}
            />
          </Grid>
        </Grid>
      </form>
    </div>
  );
}
Example #17
Source File: register-user.js    From horondi_admin with MIT License 4 votes vote down vote up
RegisterUser = ({ handleClose }) => {
  const styles = useStyles();
  const dispatch = useDispatch();

  const { loading } = useSelector(({ Users }) => ({
    loading: Users.adminLoading
  }));

  const { adminId } = useSelector(({ Auth }) => ({
    adminId: Auth.adminId
  }));

  const formSchema = Yup.object().shape({
    email: Yup.string()
      .required(ENTER_EMAIL_MESSAGE)
      .email(INVALID_EMAIL_MESSAGE),
    role: Yup.string().required(SELECT_ROLE_MESSAGE),
    otp_code: Yup.string().when('role', {
      is: superadmin,
      then: Yup.string().required(ENTER_CODE)
    })
  });

  const { handleSubmit, handleChange, values, touched, errors } = useFormik({
    initialValues: {
      role: admin,
      email: '',
      otp_code: ''
    },
    validationSchema: formSchema,
    validateOnBlur: true,
    onSubmit: (data) => {
      dispatch(registerAdmin(data));
      handleClose();
    }
  });

  const roles = userRoles.filter((item) =>
    allowedforRegistrationRoles.includes(item.role)
  );

  if (loading) {
    return <LoadingBar />;
  }

  const rolesList = roles.map((item, idx) => (
    <MenuItem key={idx} id={item.role} data-cy={item.role} value={item.role}>
      {item.label}
    </MenuItem>
  ));

  const handleSendCode = () => {
    dispatch(confirmSuperadmin({ _id: adminId }));
  };

  return (
    <Grid className={styles.detailsContainer}>
      <Grid className={styles.userDetails}>
        <form onSubmit={handleSubmit}>
          <Paper className={styles.userInputPanel}>
            <FormControl
              className={styles.formControl}
              error={touched.email && !!errors.email}
            >
              <TextField
                onChange={handleChange}
                value={values.email}
                id='email'
                variant={outlined}
                label='Пошта'
                name='email'
                data-cy='email'
                type={text}
                onBlur={handleChange}
                error={touched.email && !!errors.email}
              />
              <FormHelperText data-cy='email-error-label'>
                {touched.email && errors.email}
              </FormHelperText>
            </FormControl>
            <FormControl
              className={styles.formControl}
              error={touched.role && !!errors.role}
            >
              <InputLabel id='role-label'>Роль</InputLabel>
              <Select
                labelId='role-label'
                id='role'
                name='role'
                type={text}
                onBlur={handleChange}
                value={values.role}
                onChange={handleChange}
                className={styles.formSelect}
                data-cy='role'
                error={touched.role && !!errors.role}
              >
                {rolesList}
              </Select>
              <FormHelperText data-cy='role-error-label'>
                {touched.role && errors.role}
              </FormHelperText>
            </FormControl>
            {values.role !== admin && (
              <FormControl
                className={styles.formControl}
                error={touched.otp_code && !!errors.otp_code}
              >
                <Button
                  id='send-otp_code-button'
                  data-cy='add-user-admin-button'
                  onClick={handleSendCode}
                  variant={contained}
                  className={styles.sendButton}
                  color={primary}
                >
                  {SEND_CODE}
                </Button>
                <TextField
                  onChange={handleChange}
                  value={values.otp_code}
                  id='otp_code'
                  variant={outlined}
                  label='Код'
                  name='otp_code'
                  data-cy='otp_code'
                  type={text}
                  onBlur={handleChange}
                  error={touched.otp_code && !!errors.otp_code}
                />
                <FormHelperText data-cy='otp_code-error-label'>
                  {touched.otp_code && errors.otp_code}
                </FormHelperText>
              </FormControl>
            )}
            <FormControl className={styles.formControl}>
              <SaveButton
                type={submit}
                title='Створити'
                data-cy='submit-admin-register'
                className={styles.saveButton}
                errors={errors}
              />
            </FormControl>
          </Paper>
        </form>
      </Grid>
    </Grid>
  );
}
Example #18
Source File: index.js    From website with MIT License 4 votes vote down vote up
RegisterNpoDetails = () => {
  const dispatch = useDispatch();
  const [openTnC, setOpenTnC] = useState(false);
  const [tnc, setTnC] = useState('');
  const [values, setValues] = useState({});
  const organization = useSelector(getOrganization);
  const router = useRouter();

  const [alertTitle, setAlertTitle] = useState('');
  const [showAlert, setShowAlert] = useState(false);
  const [alertType, setAlertType] = useState('');
  const [alertDescription, setAlertDescription] = useState('');
  const [isLoading, setIsLoading] = useState(false);

  const [isPasswordSecure, setIsPasswordSecure] = useState(false);

  useEffect(() => {
    api.legal.get('tnc_npo').then((doc) => {
      setTnC(doc.data().content);
    });
  }, []);

  const handleBackToNpoRegisterOnClick = () => {
    dispatch(setIsBackToNpoRegister());
  };

  const displayAlert = (title, description, type) => {
    setShowAlert(true);
    setAlertTitle(title);
    setAlertDescription(description);
    setAlertType(type);
  };

  const handleFormSubmission = async () => {
    handleModal();
    setIsLoading(true);
    setShowAlert(false);
    dispatch(setNpoDetails(values.name, values.mobileNumber));
    try {
      let name = values.name;
      let contact = values.mobileNumber;
      let email = values.email;
      let password = values.password;
      let organizationName = organization.name;
      let registrationNumber = organization.registrationNumber;
      let activities = organization.activities;
      const [token, user, userDoc] = await api.auth.registerNPO(
        name,
        contact,
        email,
        password,
        organizationName,
        registrationNumber,
        activities
      );
      await api.auth.sendVerificationEmail();
      displayAlert(
        'Successfully Registered!',
        `A verification email has been sent to ${user.email}. Remember to check your junk email too!`,
        'success'
      );
      let response = await client.post('/api/sessionLogin', { token });
      if (response.status === 200) {
        await timeout(1000);
        router.push('/?next=onboarding');
      } else {
        throw response.error;
      }
    } catch (error) {
      console.error(error);
      await api.auth.logout();
      setIsLoading(false);
      formik.setSubmitting(false);
      if (error.code === 'auth/email-already-in-use') {
        displayAlert('Email already in use', error.message, 'critical');
      } else if (error.code === 'auth/invalid-email') {
        displayAlert('Invalid Email', error.message, 'critical');
      } else if (error.code === 'auth/unable-to-create-user') {
        displayAlert('Error', error.message, 'critical');
      } else {
        displayAlert('Error', error.message, 'critical');
      }
    }
  };

  const handleModal = () => {
    if (openTnC) {
      setOpenTnC(false);
    } else {
      setOpenTnC(true);
    }
  };

  const validationSchema = Yup.object().shape({
    name: Yup.string().required('Required'),
    mobileNumber: Yup.string()
      .required('Required')
      .matches(/^[6|8|9]\d{7}$/, 'Phone number is not valid'),
    email: Yup.string().email('Email must be a valid email').required('Required'),
    password: Yup.string()
      .required('Required')
      .matches(
        /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[\!\@\#\$%\^&\*\-\+\=\?\;\:\[\]\{\}\|\`\~\"\'\_\.])(?=.{12,})/,
        'Please create a password with at least 12 characters, comprising a mix of uppercase and lowercase letters, numbers and symbols'
      ),
    passwordConfirmation: Yup.string()
      .required('Required')
      .oneOf([Yup.ref('password'), null], 'Passwords must match'),
  });

  const formik = useFormik({
    initialValues: {
      name: '',
      mobileNumber: '',
      email: '',
      password: '',
      passwordConfirmation: '',
    },
    validationSchema: validationSchema,
    onSubmit: (values) => {
      handleModal();
      setValues(values);
    },
  });

  return (
    <div>
      <Button
        type="secondary"
        circled
        iconLeft={<ChevronLeft />}
        onClick={handleBackToNpoRegisterOnClick}
        spaceAfter="normal"
      />
      <form onSubmit={formik.handleSubmit}>
        <Stack spacing="loose">
          <InputField
            disabled={formik.isSubmitting}
            label="Name"
            name="name"
            placeholder="Your full name"
            error={formik.touched.name && formik.errors.name ? formik.errors.name : ''}
            {...formik.getFieldProps('name')}
            help={
              <Tooltip
                content="Use your own name even though there might be multiple people sharing a single account."
                enabled
                preferredAlign="start"
                preferredPosition="bottom"
                size="medium"
              >
                <span>Not sure whose name to put?</span>
              </Tooltip>
            }
          />
          <InputField
            prefix="+65"
            disabled={formik.isSubmitting}
            label="Mobile Number"
            name="mobileNumber"
            placeholder="Mobile Number or Your desk number"
            error={formik.touched.mobileNumber && formik.errors.mobileNumber ? formik.errors.mobileNumber : ''}
            {...formik.getFieldProps('mobileNumber')}
          />
          <InputField
            disabled={formik.isSubmitting}
            type="email"
            value="[email protected]"
            label="Email"
            name="email"
            autoComplete="email"
            placeholder="e.g. [email protected]"
            help="Please use your work email"
            error={formik.touched.email && formik.errors.email ? formik.errors.email : ''}
            {...formik.getFieldProps('email')}
          />
          <Stack spacing="none">
            <InputField
              disabled={formik.isSubmitting}
              type="password"
              label="Create a password"
              name="password"
              autoComplete="new-password"
              error={formik.touched.password && formik.errors.password ? true : false}
              {...formik.getFieldProps('password')}
              suffix={
                isPasswordSecure ? (
                  <CheckIconWrapper>
                    <Check />
                  </CheckIconWrapper>
                ) : null
              }
            />

            {formik.touched.password && formik.errors.password ? (
              <Text size="small" type="critical" weight="bold">
                {formik.errors.password}
              </Text>
            ) : (
              <Text size="small" type="secondary">
                Please create a password with at least 12 characters, comprising a mix of uppercase and lowercase
                letters, numbers and symbols
              </Text>
            )}
          </Stack>
          <PasswordStrength
            password={formik.values.password}
            show={formik.errors.password && formik.values.password.length > 0 ? true : false}
            onSecure={() => {
              setIsPasswordSecure(true);
            }}
            onNotSecure={() => {
              setIsPasswordSecure(false);
            }}
          />
          <InputField
            disabled={formik.isSubmitting}
            type="password"
            label="Confirm password"
            name="passwordConfirm"
            autoComplete="new-password"
            error={
              formik.touched.passwordConfirmation && formik.errors.passwordConfirmation
                ? formik.errors.passwordConfirmation
                : ''
            }
            {...formik.getFieldProps('passwordConfirmation')}
          />
          {showAlert ? (
            <Alert icon title={alertTitle} type={alertType}>
              {alertDescription}
            </Alert>
          ) : null}
          <Button submit fullWidth={true} asComponent={BlueButton} loading={isLoading}>
            Register
          </Button>
          <Text align="center" type="secondary">
            By joining, you agree to the{' '}
            <TextLink type="secondary" external href="https://www.giftforgood.io/privacy-policy">
              Privacy Policy
            </TextLink>{' '}
            and our{' '}
            <TextLink type="secondary" external href="https://www.giftforgood.io/terms-and-conditions">
              Terms and Conditions
            </TextLink>
            .
          </Text>
        </Stack>
      </form>

      {openTnC ? <TermsAndConditionModal onClose={handleModal} tnc={tnc} onSubmit={handleFormSubmission} /> : null}
    </div>
  );
}
Example #19
Source File: Edit.js    From course-manager with MIT License 4 votes vote down vote up
// ----------------------------------------------------------------------

export default function Edit() {
  const navigate = useNavigate();
  const { id } = useParams();
  const [course, setCourse] = useState();
  const [videos, setVideos] = useState([]);
  const [isVideoModelOpen, setVideoModelOpen] = useState(false);
  const [thumbnailUrl, setThumbnailUrl] = useState('');
  useEffect(() => {
    async function fetchCourse() {
      const queryString = RequestQueryBuilder.create({
        join: {
          field: 'videos'
        }
      });
      const course = await apis.course.findOne(id, queryString.query());
      if (!course) navigate('/dashboard/courses', { replace: true });
      formik.initialValues = {
        title: course.title,
        description: course.description
      };
      setCourse(course);
      setVideos(course.videos);
      setThumbnailUrl(course.thumbnailUrl);
    }
    fetchCourse();
  }, []);

  const CourseSchema = Yup.object().shape({
    title: Yup.string().required('Full name is required'),
    description: Yup.string().required('Username is required')
  });

  const formik = useFormik({
    initialValues: course,
    enableReinitialize: true,
    validationSchema: CourseSchema,
    onSubmit: async (values) => {
      const data = {
        ...values,
        thumbnailUrl
      };
      const updatedCourse = await apis.course.update(id, data);
      if (!updatedCourse) {
        return;
      }
      navigate('/dashboard/courses', { replace: true });
    }
  });

  const { errors, touched, isSubmitting, handleSubmit, getFieldProps } = formik;
  const closeVideoForm = (e, reason) => {
    if (reason !== 'backdropClick') setVideoModelOpen(false);
  };

  const videoCreatedHandler = (newVideo) => {
    setVideos([...videos, newVideo]);
  };

  return (
    <Page title="List | Minimal-UI">
      <Container>
        <VideoCreateForm
          open={isVideoModelOpen}
          onClose={closeVideoForm}
          onDataCreated={videoCreatedHandler}
        />
        <Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
          <Typography variant="h4" gutterBottom>
            Edit Course
          </Typography>
        </Stack>
        {course && (
          <FormikProvider value={formik}>
            <Form autoComplete="off" noValidate onSubmit={handleSubmit}>
              <Stack spacing={3}>
                <TextField
                  fullWidth
                  autoComplete="title"
                  type="text"
                  label="Title"
                  {...getFieldProps('title')}
                  error={Boolean(touched.title && errors.title)}
                  helperText={touched.title && errors.title}
                />
                <TextField
                  fullWidth
                  autoComplete="description"
                  type="text"
                  label="Description"
                  {...getFieldProps('description')}
                  error={Boolean(touched.description && errors.description)}
                  helperText={touched.description && errors.description}
                />
                <FileUploader
                  initUrl={thumbnailUrl}
                  type={COURSE_THUMBNAIL_TYPE}
                  setUrl={setThumbnailUrl}
                  title="Upload thumbnail"
                  name="edit-course-thumb"
                />
                <Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
                  <Typography variant="h5" gutterBottom>
                    Videos
                  </Typography>
                  <Button
                    variant="contained"
                    onClick={() => setVideoModelOpen(true)}
                    startIcon={<Icon icon={plusFill} />}
                  >
                    Add video
                  </Button>
                </Stack>
                {videos && (
                  <Grid container spacing={3}>
                    {videos.map((video) => (
                      <Grid key={video.id} item xs={12} sm={6} md={3}>
                        <VideoCard video={video} />
                      </Grid>
                    ))}
                  </Grid>
                )}
                <LoadingButton
                  fullWidth
                  size="large"
                  type="submit"
                  variant="contained"
                  loading={isSubmitting}
                >
                  Submit
                </LoadingButton>
              </Stack>
            </Form>
          </FormikProvider>
        )}
        <Card />
      </Container>
    </Page>
  );
}
Example #20
Source File: index.js    From website with MIT License 4 votes vote down vote up
NpoEditProfilePanel = () => {
  const user = useUser();
  const [profileImage, setProfileImage] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const router = useRouter();

  const [alertTitle, setAlertTitle] = useState('');
  const [showAlert, setShowAlert] = useState(false);
  const [alertType, setAlertType] = useState('');
  const [alertDescription, setAlertDescription] = useState('');

  const displayAlert = (title, description, type) => {
    setShowAlert(true);
    setAlertTitle(title);
    setAlertDescription(description);
    setAlertType(type);
  };

  const handleFormSubmission = async (values) => {
    setIsLoading(true);
    setShowAlert(false);
    const { name, contactNumber, profileImage } = values;
    try {
      const npoDoc = await api.users.updateNPO(name, contactNumber, profileImage);
      setIsLoading(false);
      router.reload();
    } catch (error) {
      setIsLoading(true);
      formik.setSubmitting(false);
      displayAlert('Error', error.message, 'critical');
    }
  };

  const validationSchema = Yup.object().shape({
    name: Yup.string().required('Required'),
    contactNumber: Yup.string()
      .required('Required')
      .matches(/^[6|8|9]\d{7}$/, 'Phone number is not valid'),
    profileImage: Yup.mixed(),
  });

  const formik = useFormik({
    initialValues: {
      name: user ? user.name : '',
      contactNumber: user ? user.contactNumber : '',
      profileImage: null,
    },
    enableReinitialize: true,
    validationSchema: validationSchema,
    onSubmit: (values) => {
      handleFormSubmission(values);
    },
  });

  const handleUploadProfileImage = (file) => {
    if (!file) {
      return;
    }

    if (file.size <= MAXIMUM_FILE_SIZE_LIMIT) {
      formik.setFieldValue('profileImage', file);
    } else {
      formik.setFieldError('profileImage', 'Unable to upload images that are more than 25mb');
    }
  };

  useEffect(() => {
    if (formik.values.profileImage) {
      const file = formik.values.profileImage;
      const reader = new FileReader();
      reader.onload = (ev) => {
        setProfileImage(ev.target.result);
      };
      reader.readAsDataURL(file);
    }
  }, [formik]);

  if (!user) {
    return null;
  }

  return (
    <Container>
      <Card>
        <CardSection>
          <form onSubmit={formik.handleSubmit}>
            <Stack spacing="loose">
              <Heading>Edit Profile</Heading>

              <Stack>
                <Heading type="title2">Profile Picture</Heading>
                <ProfileAvatar imageUrl={profileImage || user.profileImageUrl.raw} height={100} width={100} />
                <InputFile
                  buttonLabel="Upload picture"
                  allowedFileTypes={['image/*']}
                  {...formik.getFieldProps('profileImage')}
                  error={formik.touched.profileImage && formik.errors.profileImage ? formik.errors.profileImage : ''}
                  fileName={formik.values.profileImage ? formik.values.profileImage.name : ''}
                  onChange={(event) => handleUploadProfileImage(event.currentTarget.files[0])}
                />
              </Stack>

              <Stack>
                <Heading type="title2">Public Profile</Heading>

                <Stack spacing="loose" spaceAfter="normal">
                  <InputField
                    disabled={formik.isSubmitting}
                    {...formik.getFieldProps('name')}
                    label="Your Name"
                    name="name"
                    placeholder="Your full name"
                    error={formik.touched.name && formik.errors.name ? formik.errors.name : ''}
                  />

                  <InputField
                    disabled={formik.isSubmitting}
                    {...formik.getFieldProps('contactNumber')}
                    label="Your Contact"
                    name="contactNumber"
                    placeholder="Your contact"
                    error={
                      formik.touched.contactNumber && formik.errors.contactNumber ? formik.errors.contactNumber : ''
                    }
                  />

                  <InputField
                    disabled
                    label="Your Email"
                    name="email"
                    placeholder="Your email"
                    value={user.email}
                    help={
                      <div>
                        Looking to change your email?{' '}
                        <TextLink external href="/contact">
                          Contact the administrators
                        </TextLink>
                      </div>
                    }
                  />
                  <InputField
                    disabled
                    label="Organization Name"
                    name="name"
                    placeholder="Your full name"
                    value={user.organization.name}
                  />

                  <InputField
                    disabled
                    label="Organization Address"
                    name="address"
                    placeholder="Address"
                    value={user.organization.address}
                  />

                  <div>
                    <Text size="small">
                      Looking to change the fields above?{' '}
                      <TextLink external href="/contact">
                        Contact the administrators
                      </TextLink>
                    </Text>
                  </div>

                  <Button
                    asComponent={SaveChangesButton}
                    submit
                    fullWidth={true}
                    disabled={formik.isSubmitting || !formik.dirty}
                    loading={isLoading}
                  >
                    Save changes
                  </Button>
                </Stack>
              </Stack>

              {showAlert ? (
                <Alert icon title={alertTitle} type={alertType}>
                  {alertDescription}
                </Alert>
              ) : null}
            </Stack>
          </form>
        </CardSection>
      </Card>
    </Container>
  );
}
Example #21
Source File: Create.js    From course-manager with MIT License 4 votes vote down vote up
// ----------------------------------------------------------------------

export default function Create() {
  const navigate = useNavigate();
  const [isAdmin, setIsAdmin] = useState(false);
  const [isMod, setIsMod] = useState(false);
  const [isSupporter, setIsSupporter] = useState(false);

  const UserSchema = Yup.object().shape({
    fullName: Yup.string().required('Full name is required'),
    username: Yup.string().required('Username is required'),
    email: Yup.string().email('Email must be a valid email address').required('Email is required')
  });

  const formik = useFormik({
    initialValues: {
      fullName: '',
      username: '',
      email: ''
    },
    validationSchema: UserSchema,
    onSubmit: async (values) => {
      const roles = [];
      if (isAdmin) roles.push('ADMIN');
      if (isSupporter) roles.push('SUPPORTER');
      if (isMod) roles.push('MOD');

      const newUser = await apis.user.create({
        ...values,
        roles
      });
      console.log(`New user ${newUser.username}`);
      navigate('/dashboard/user', { replace: true });
    }
  });

  const handleChange = (event) => {
    switch (event.target.name) {
      case 'isAdmin':
        setIsAdmin(event.target.checked);
        if (event.target.checked) {
          setIsMod(false);
          setIsSupporter(false);
        }
        break;
      case 'isMod':
        setIsMod(event.target.checked);
        break;
      case 'isSupporter':
        setIsSupporter(event.target.checked);
        break;
      default:
        break;
    }
  };

  const { errors, touched, isSubmitting, handleSubmit, getFieldProps } = formik;

  return (
    <Page title="List | Minimal-UI">
      <Container>
        <Stack direction="row" alignItems="center" justifyContent="space-between" mb={5}>
          <Typography variant="h4" gutterBottom>
            Edit User
          </Typography>
          <Button
            variant="contained"
            component={RouterLink}
            to="#"
            startIcon={<Icon icon={plusFill} />}
          >
            New List
          </Button>
        </Stack>
        <FormikProvider value={formik}>
          <Form autoComplete="off" noValidate onSubmit={handleSubmit}>
            <Stack spacing={3}>
              <TextField
                fullWidth
                autoComplete="username"
                type="text"
                label="Username"
                {...getFieldProps('username')}
                error={Boolean(touched.username && errors.username)}
                helperText={touched.username && errors.username}
              />
              <TextField
                fullWidth
                autoComplete="fullName"
                type="text"
                label="Full name"
                {...getFieldProps('fullName')}
                error={Boolean(touched.fullName && errors.fullName)}
                helperText={touched.fullName && errors.fullName}
              />
              <TextField
                fullWidth
                autoComplete="email"
                type="email"
                label="Email"
                {...getFieldProps('email')}
                error={Boolean(touched.email && errors.email)}
                helperText={touched.email && errors.email}
              />
              <FormControlLabel
                control={<ODCheckbox checked={isAdmin} onChange={handleChange} name="isAdmin" />}
                label="Is Admin"
              />
              <FormGroup row>
                <FormControlLabel
                  disabled={isAdmin}
                  control={<ODCheckbox checked={isMod} onChange={handleChange} name="isMod" />}
                  label="Is Mod"
                />
                <FormControlLabel
                  disabled={isAdmin}
                  control={
                    <ODCheckbox checked={isSupporter} onChange={handleChange} name="isSupporter" />
                  }
                  label="Is Supporter"
                />
              </FormGroup>
              <LoadingButton
                fullWidth
                size="large"
                type="submit"
                variant="contained"
                loading={isSubmitting}
              >
                Submit
              </LoadingButton>
            </Stack>
          </Form>
        </FormikProvider>
        <Card />
      </Container>
    </Page>
  );
}
Example #22
Source File: index.js    From website with MIT License 4 votes vote down vote up
RegisterDonor = () => {
  const dispatch = useDispatch();
  const router = useRouter();
  const [alertTitle, setAlertTitle] = useState('');
  const [showAlert, setShowAlert] = useState(false);
  const [alertType, setAlertType] = useState('');
  const [alertDescription, setAlertDescription] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const [googleLoading, setGoogleLoading] = useState(false);

  const [isPasswordSecure, setIsPasswordSecure] = useState(false);

  const handleBackToLandingOnClick = () => {
    dispatch(setIsBackToLanding());
  };

  const displayAlert = (title, description, type) => {
    setShowAlert(true);
    setAlertTitle(title);
    setAlertDescription(description);
    setAlertType(type);
  };

  const handleFormSubmission = async (values) => {
    try {
      setIsLoading(true);
      const [token, user, userDoc] = await api.auth.registerDonorWithEmailAndPassword(values.email, values.password);
      await api.auth.sendVerificationEmail();
      displayAlert('Successfully Registered!', `A verification email has been sent to ${user.email}`, 'success');
      let response = await client.post('/api/sessionLogin', { token });
      if (response.status === 200) {
        await timeout(1000);
        router.push('/?next=onboarding');
      } else {
        throw response.error;
      }
    } catch (error) {
      console.error(error);
      await api.auth.logout();
      setIsLoading(false);
      formik.setSubmitting(false);
      if (error.code === 'auth/email-already-in-use') {
        displayAlert('Email already in use', error.message, 'critical');
      } else if (error.code === 'auth/invalid-email') {
        displayAlert('Invalid Email', error.message, 'critical');
      } else if (error.code === 'auth/unable-to-create-user') {
        displayAlert('Error', error.message, 'critical');
      } else {
        displayAlert('Error', error.message, 'critical');
      }
    }
  };

  const handleGoogleRegister = async () => {
    try {
      setGoogleLoading(true);
      const [token, user, userDoc] = await api.auth.registerDonorWithGoogle();
      let response = await client.post('/api/sessionLogin', { token });
      if (response.status === 200) {
        await timeout(1000);
        router.push('/');
      } else {
        throw response.error;
      }
    } catch (error) {
      console.error(error);
      await api.auth.logout();
      setGoogleLoading(false);
      if (error.code === 'auth/unable-to-create-user') {
        displayAlert('Error', error.message, 'critical');
      } else {
        displayAlert('Error', error.message, 'critical');
      }
    }
  };

  const validationSchema = Yup.object().shape({
    email: Yup.string().email('Email must be a valid email').required('Required'),
    password: Yup.string()
      .required('Required')
      .matches(
        /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[\!\@\#\$%\^&\*\-\+\=\?\;\:\[\]\{\}\|\`\~\"\'\_\.])(?=.{12,})/,
        'Please create a password with at least 12 characters, comprising a mix of uppercase and lowercase letters, numbers and symbols'
      ),
    passwordConfirmation: Yup.string()
      .required('Required')
      .oneOf([Yup.ref('password'), null], 'Passwords must match'),
  });

  const formik = useFormik({
    initialValues: {
      email: '',
      password: '',
      passwordConfirmation: '',
    },
    validationSchema: validationSchema,
    onSubmit: (values) => {
      handleFormSubmission(values);
    },
  });

  return (
    <div>
      <Button
        type="secondary"
        circled
        iconLeft={<ChevronLeft />}
        onClick={handleBackToLandingOnClick}
        spaceAfter="normal"
      />
      <Text align="center" as="div" spaceAfter="largest">
        <Stack direction="row" align="center" justify="center">
          <Heading size="large" weight="bold">
            I am a
          </Heading>
          <Heading size="large" weight="bold">
            <HeadingColor>Donor</HeadingColor>
          </Heading>
        </Stack>
      </Text>
      <SocialButton
        type="google"
        fullWidth={true}
        spaceAfter="normal"
        onClick={handleGoogleRegister}
        loading={googleLoading}
        disabled={isLoading}
      >
        Sign in with Google
      </SocialButton>
      <Text align="center" spaceAfter="normal">
        OR
      </Text>
      <form onSubmit={formik.handleSubmit}>
        <Stack spacing="comfy" spaceAfter="normal">
          <InputField
            disabled={formik.isSubmitting}
            type="email"
            value="[email protected]"
            label="Email"
            name="email"
            autoComplete="email"
            placeholder="e.g. [email protected]"
            error={formik.touched.email && formik.errors.email ? formik.errors.email : ''}
            {...formik.getFieldProps('email')}
          />

          <Stack spacing="none">
            <InputField
              disabled={formik.isSubmitting}
              type="password"
              label="Create a password"
              name="password"
              autoComplete="new-password"
              error={formik.touched.password && formik.errors.password ? true : false}
              {...formik.getFieldProps('password')}
              suffix={
                isPasswordSecure ? (
                  <CheckIconWrapper>
                    <Check />
                  </CheckIconWrapper>
                ) : null
              }
            />

            {formik.touched.password && formik.errors.password ? (
              <Text size="small" type="critical" weight="bold">
                {formik.errors.password}
              </Text>
            ) : (
              <Text size="small" type="secondary">
                Please create a password with at least 12 characters, comprising a mix of uppercase and lowercase
                letters, numbers and symbols
              </Text>
            )}
          </Stack>

          <PasswordStrength
            password={formik.values.password}
            show={formik.errors.password && formik.values.password.length > 0 ? true : false}
            onSecure={() => {
              setIsPasswordSecure(true);
            }}
            onNotSecure={() => {
              setIsPasswordSecure(false);
            }}
          />

          <InputField
            disabled={formik.isSubmitting}
            type="password"
            label="Confirm password"
            name="passwordConfirm"
            autoComplete="new-password"
            error={
              formik.touched.passwordConfirmation && formik.errors.passwordConfirmation
                ? formik.errors.passwordConfirmation
                : ''
            }
            {...formik.getFieldProps('passwordConfirmation')}
          />

          <Button
            submit
            fullWidth={true}
            asComponent={RedButton}
            disabled={formik.isSubmitting}
            loading={isLoading}
            disabled={googleLoading}
          >
            Register
          </Button>
          <Text align="center" type="secondary">
            By joining, you agree to the{' '}
            <TextLink type="secondary" external href="https://www.giftforgood.io/privacy-policy">
              Privacy Policy
            </TextLink>{' '}
            and our{' '}
            <TextLink type="secondary" external href="https://www.giftforgood.io/terms-and-conditions">
              Terms and Conditions
            </TextLink>
            .
          </Text>
        </Stack>
      </form>

      {showAlert ? (
        <Alert icon title={alertTitle} type={alertType}>
          {alertDescription}
        </Alert>
      ) : null}
    </div>
  );
}
Example #23
Source File: index.js    From flame-coach-web with MIT License 4 votes vote down vote up
CustomersView = ({ customerIdentifier }) => {
  const classes = useStyles();
  const isMobile = useIsMediumMobile();

  const options = {
    filterType: "dropdown",
    selectableRows: "none",
    tableBodyMaxHeight: "70vh",
    sortOrder: {
      name: "Name",
      direction: "asc"
    },
    print: false
  };
  const [notification, setNotification] = useState({
    enable: false,
    message: "",
    level: "INFO"
  });

  const queryClient = useQueryClient();

  const [clientLoading, setClientLoading] = useState(false);
  const [isClientLoading, setIsClientLoading] = useState(null);

  const { mutate: inviteClient } = useInviteClient();

  const resetNotificationHandler = () => {
    setNotification(update(notification,
      {
        enable: { $set: false }
      }));
  };

  const updateNotificationHandler = (enable, message, level) => {
    setNotification({
      enable,
      message,
      level
    });
  };

  const formikSendInviteClient = useFormik({
    initialValues: {
      email: ""
    },

    validationSchema,
    validateOnBlur: false,
    validateOnChange: false,
    onSubmit: (values) => {
      inviteClient({
        coachIdentifier: customerIdentifier,
        clientEmail: values.email
      }, {
        onError: (error) => {
          logError("Customer",
            "useMutation inviteClient",
            "Error:", error.response);

          logError("Customer", "useMutation inviteClient", "Error Details:", error.response.data.detail);
          const errorCode = ErrorMessage.fromCode(error.response.data.code);
          updateNotificationHandler(true, errorCode.msg, errorCode.level);
        },
        onSuccess: (data) => {
          queryClient.invalidateQueries(["getClientsCoachPlusClientsAvailableForCoaching", customerIdentifier]);

          const successMessage = data.registrationInvite ? InfoMessage.CODE_0004
            : InfoMessage.CODE_0003;

          updateNotificationHandler(true, successMessage.msg, successMessage.level);
        }
      });
    }
  });

  const {
    isError,
    isLoading,
    data
  } = useQuery(["getClientsCoachPlusClientsAvailableForCoaching", customerIdentifier],
    () => getClientsCoachPlusClientsAvailableForCoaching(customerIdentifier), {
      onError: async (err) => {
        logError("Customer",
          "useQuery getClientsCoachPlusClientsAvailableForCoaching",
          "Error:", err);
      },
      select: (data) => {
        const filteredClients = data.clientsCoach.filter((client) => client.status === "PENDING"
          || client.status === "ACCEPTED");

        return {
          identifier: data.identifier,
          clientsCoach: filteredClients
        };
      }
    });

  const unlinkClient = useMutation(
    ({
      clientIdentifier,
      // eslint-disable-next-line no-unused-vars
      coachIdentifier
    }) => enrollmentProcessBreak(clientIdentifier),
    {
      onMutate: async ({ clientIdentifier }) => {
        setClientLoading(clientIdentifier);
        setIsClientLoading(true);
        resetNotificationHandler();
      },
      onError: async (error) => {
        logError("Customer",
          "useMutation enrollmentProcessBreak",
          "Error:", error.response);
        setIsClientLoading(false);

        logError("Customer", "useMutation enrollmentProcessBreak", "Error Details:", error.response.data.detail);
        const errorCode = ErrorMessage.fromCode(error.response.data.code);
        updateNotificationHandler(true, errorCode.msg, errorCode.level);
      },
      onSuccess: async (data, variables) => {
        await queryClient.cancelQueries(["getClientsCoachPlusClientsAvailableForCoaching", variables.coachIdentifier]);

        queryClient.setQueryData(["getClientsCoachPlusClientsAvailableForCoaching", customerIdentifier], (oldData) => {
          const index = oldData.clientsCoach.findIndex(
            (customer) => customer.identifier === variables.clientIdentifier
          );

          return update(oldData, {
            clientsCoach: {
              [index]: {
                status: { $set: data.status }
              }
            }
          });
        });

        setIsClientLoading(false);
      }
    }
  );

  const unlinkClientHandler = (client) => {
    unlinkClient.mutate({
      clientIdentifier: client.identifier,
      coachIdentifier: customerIdentifier
    });
  };

  const getStatus = (status) => {
    switch (status) {
      case "AVAILABLE":
        return "Available";
      case "PENDING":
        return "Pending";
      case "ACCEPTED":
        return "My client";
      default:
        return "Unknown";
    }
  };

  const columnActions = {
    label: "Actions",
    options: {
      filter: false,
      sort: false,
      setCellHeaderProps: () => {
        return {
          className: clsx({
            [classes.rightTableHead]: true
          })
        };
      },
      // eslint-disable-next-line react/display-name
      customBodyRender: (value) => {
        const disableButtonMinus = value.client.identifier === value.clientLoading
          ? value.isClientLoading || !(value.client.status !== "AVAILABLE")
          : !(value.client.status !== "AVAILABLE");

        return (
          <Grid
            container
            justifyContent={isMobile ? "flex-start" : "flex-end"}
            spacing={1}
            className={clsx({
              [classes.actionColumnTable]: true
            })}
          >
            <Grid item>
              <Button
                className={classes.minusUserButton}
                variant="contained"
                disabled={disableButtonMinus}
                onClick={() => unlinkClientHandler(value.client)}
              >
                <SvgIcon
                  fontSize="small"
                  color="inherit"
                >
                  <UserMinusIcon />
                </SvgIcon>
              </Button>
            </Grid>
          </Grid>
        );
      }
    }
  };

  const columns = ["Name", "Email", "Registration date", "Status", columnActions];

  return (
    <Page
      title="Customers"
      isError={isError}
      isLoading={isLoading}>
      <Grid
        direction="row"
        container
      >
        <Grid item xs={12}>
          <Box marginBottom={2}>
            <form onSubmit={formikSendInviteClient.handleSubmit}>
              <Card>
                <CardContent>
                  <Typography gutterBottom variant="h5" component="h2">
                    Send Invite
                  </Typography>
                  <Box className={classes.sendCard}>
                    <TextField
                      error={Boolean(formikSendInviteClient.errors.email)}
                      fullWidth
                      helperText={formikSendInviteClient.errors.email}
                      label="Email"
                      margin="normal"
                      name="email"
                      onBlur={formikSendInviteClient.handleBlur}
                      onChange={formikSendInviteClient.handleChange}
                      value={formikSendInviteClient.values.email}
                      variant="outlined"
                    />
                    <Button
                      className={classes.sendInviteButton}
                      variant="contained"
                      type="submit"
                    >
                      <SvgIcon
                        fontSize="small"
                        color="inherit"
                      >
                        <SendIcon />
                      </SvgIcon>
                    </Button>
                  </Box>
                </CardContent>
              </Card>
            </form>
          </Box>
        </Grid>
        <Grid item xs={12}>
          <Table
            title="Clients List"
            data={data ? data.clientsCoach.map((client) => ([
              `${client.firstname} ${client.lastname}`,
              client.email,
              client.registrationDate,
              getStatus(client.status),
              {
                client,
                clientLoading,
                isClientLoading
              }
            ])) : null}
            columns={columns}
            options={options}
            themeTable={outerTheme => outerTheme}
          />
        </Grid>
        {notification.enable
          ? (
            <Grid item xs={12}>
              <Notification
                collapse
                open={notification.enable}
                openHandler={resetNotificationHandler}
                level={notification.level}
                message={notification.message}
              />
            </Grid>
          )
          : null}
      </Grid>
    </Page>
  );
}
Example #24
Source File: Reviews.js    From Next.js-e-commerce-online-store with MIT License 4 votes vote down vote up
export default function Reviews({ id, reviewList }) {

  const [ isEditorReadOnly, setIsEditorReadOnly ] = useState(false)
  const [ sameEmailError, setSameEmailError ] = useState(false)

  const formik = useFormik({
    initialValues: { name: '', email: '', message: '' },
    onSubmit: async (values, { resetForm }) => {

      setIsEditorReadOnly(true)

      await fetch(`/api/postReview?productId=${id}&name=${values.name}&email=${values.email}&reviewText=${encodeURIComponent(values.message)}`)
        .then(res => {
          if (res.status >= 400) {

            if (res.status === 400) {
              console.log(res.status, res)
              setSameEmailError(res.statusText)

              const err = new Error(res.statustext)

              setIsEditorReadOnly(false)

              throw err
            } else if (res.status > 400) {
              setSameEmailError(false)

              const err = new Error('Error')
  
              setIsEditorReadOnly(false)
  
              throw err
            }
          }
          return res.json()
        })
        .then(data => {
          resetForm()
          setEditorState(EditorState.push(editorState, ContentState.createFromText('')))

          setSameEmailError(false)
          
          const publishedReview = data.data.createReview.data    
          reviewList.push(publishedReview)
    
          setIsEditorReadOnly(false)

          const headingElement = document.getElementById('heading')
          headingElement.scrollIntoView({ behavior: 'smooth' })
        })
        .catch(err => console.error(err))
    },
    validationSchema: schema
  })

  const [ reviews, setReviews ] = useState(reviewList)

  const value = formik.values.message
  
  const prepareDraft = value => {
    const draft = htmlToDraft(value)
    const contentState = ContentState.createFromBlockArray(draft.contentBlocks)
    const editorState = EditorState.createWithContent(contentState)

    return editorState
  }

  const setFieldValue = val => formik.setFieldValue('message', val)

  const [ editorState, setEditorState ] = useState(value ? prepareDraft(value) : EditorState.createEmpty())

  const onEditorStateChange = editorState => {
    const forFormik = draftToHtml(
      convertToRaw(editorState.getCurrentContent())
    )
    setFieldValue(forFormik)
    setEditorState(editorState)
  }

  return (
    <ReviewsDiv>
      <div className="heading" id="heading">
        {
          reviews.length === 0
          ? 'No reviews so far. Be the first!'
          : 'Reviews'
        }
      </div>
      <div className="reviews">
        {
          reviews
            .sort((a, b) => (
              // sort by date, newest first ↓
              new Date(b.attributes.createdAt).getTime() - new Date(a.attributes.createdAt).getTime()
            ))
            .map(review => (
              <div className="review" key={review.id}>
                <div>
                  Reviewed at <b>{review.attributes.createdAt.slice(0, 10)}</b> by <b>{review.attributes.name}</b>:
                </div>
                <div dangerouslySetInnerHTML={{__html: review.attributes.reviewText}} className="review-text"></div>
              </div>
            ))
        }
      </div>
      <form className="form" onSubmit={formik.handleSubmit}>
        <div className="input-group">
          <div className="input-group-prepend">
            <span className="input-group-text" id="inputGroup-sizing-default">Name</span>
          </div>
          <input 
            type="text" 
            aria-label="Sizing example input" 
            aria-describedby="inputGroup-sizing-default" 
            pattern="[A-Za-z ]{1,32}"
            title="1 to 32 letters, no special symbols, except space"
            minLength="1"
            name="name"
            id="name" 
            required
            className="form-control" 
            value={formik.values.name}
            onChange={formik.handleChange}
          />
        </div>
        {formik.errors.name && <h1 className="feedback-msgs">{formik.errors.name}</h1>}
        <div className="input-group">
          <div className="input-group-prepend">
            <span className="input-group-text" id="inputGroup-sizing-default">E-mail</span>
          </div>
          <input 
            type="email" 
            aria-label="Sizing example input" 
            aria-describedby="inputGroup-sizing-default" 
            minLength="3"
            name="email"
            id="email"
            required
            className="form-control" 
            value={formik.values.email}
            onChange={formik.handleChange}
          />
        </div>
        {formik.errors.email && <h1 className="feedback-msgs">{formik.errors.email}</h1>}
        <div className="editor-top-wrapper">        
          <Editor
            editorState={editorState}
            readOnly={isEditorReadOnly}
            toolbarHidden={isEditorReadOnly}
            toolbarClassName="toolbar"
            wrapperClassName="wrapper"
            editorClassName="editor"
            onEditorStateChange={onEditorStateChange}
            toolbar={{
              options: ['inline', 'blockType', 'fontSize', 'fontFamily', 'list', 'textAlign', 'colorPicker', 'link', 'embedded', 'emoji', 'image', 'remove', 'history'],
              colorPicker: { popupClassName: 'colorPickerPopup' },
              link: { popupClassName: 'linkPopup' },
              emoji: { popupClassName: 'emojiPopup' },
              embedded: { popupClassName: 'embeddedPopup' },
              image: { popupClassName: 'imagePopup' }
            }}
          />
        </div>
        {formik.errors.message && <div className="feedback-msgs">{formik.errors.message}</div>}
        {
          sameEmailError 
          ? <div className="feedback-msgs">{sameEmailError}</div> 
          : null
        }
        <button type="submit" className="post-button btn btn-primary" disabled={isEditorReadOnly}>
          Post Review
        </button>
      </form>
    </ReviewsDiv>
  )
}
Example #25
Source File: index.js    From atendimento-e-agilidade-medica-AAMed with MIT License 4 votes vote down vote up
Login = () => {
  const [showPass, setShowPass] = useState(true);
  const [press, setPress] = useState(false);
  const [errorMsg, setErrorMsg] = useState(false);
  const navigation = useNavigation();
  const [auth, { login }] = useAuth();

  const formik = useFormik({
    initialValues: {
      cpf: '',
      password: '',
    },
    onSubmit: async values => {
      try {
        const response = await api.post('/login/user', values);

        login(response.data);
        console.log(response.data); //debug
      } catch (error) {
        // Error
        if (error.response) {
          setErrorMsg(error.response.data.error);
          console.log(error.response.data);
        } else if (error.request) {
          console.log(error.request);
        } else {
          console.log('Error', error.message);
        }
        // setErrorMsg(error.message); // depois vejo isso
        console.log('Erro fora dos ifs ', error); // depois de 2min que vai aparecer
      }
    },
  });

  function toggleShowPass() {
    if (!press) {
      setShowPass(false);
      setPress(true);
    } else {
      setShowPass(true);
      setPress(false);
    }
  }

  navigation.setOptions({
    headerRight: () => (
      <Button
        onPress={() => navigation.navigate('SignUp')}
        title="Cadastre-se"
        color="#0277BD"
      />
    ),
    headerRightContainerStyle: {
      padding: 15,
    },
    title: 'Bem-Vindo',
  });

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <ImageBackground source={screen} style={{ flex: 1 }}>
        <KeyboardAvoidingView
          keyboardVerticalOffset={0}
          enabled={false}
          behavior="padding"
          style={{ flex: 1 }}
        >
          <ImageContainer>
            <Image source={logo} resizeMode="contain" />
          </ImageContainer>

          {!!errorMsg && <ErrorText>{errorMsg}</ErrorText>}
          <LoginBox>
            <InputBox>
              {/* <Icon name="user" /> */}
              <Label>CPF</Label>
              <InputMask
                name="cpf"
                type={'cpf'}
                placeholder="000.000.000-00"
                placeholderTextColor="#00000066"
                returnKeyType="next"
                selectionColor="#006bad66"
                value={formik.values.cpf}
                onChangeText={formik.handleChange('cpf')}
              />
            </InputBox>

            <InputBox>
              {/* <Icon name="lock" /> */}
              <Label>Senha</Label>
              <Input
                name="password"
                secureTextEntry={showPass}
                placeholder="************"
                placeholderTextColor="#00000066"
                returnKeyType="done"
                selectionColor="#006bad66"
                value={formik.values.password}
                onChangeText={formik.handleChange('password')}
              />
              <TouchEye onPress={toggleShowPass}>
                <IconEye name={press ? 'eye-off-outline' : 'eye-outline'} />
              </TouchEye>
            </InputBox>

            <MainButton
              onPress={formik.handleSubmit}
              flag={formik.isSubmitting}
              label={'ENTRAR'}
            >
              <ActivityIndicator size="small" color="#FFF" />
            </MainButton>
            <Option
              onPress={() => {
                navigation.navigate('ForgotPassword');
              }}
            >
              Esqueceu a senha?
            </Option>
          </LoginBox>
        </KeyboardAvoidingView>
      </ImageBackground>
    </SafeAreaView>
  );
}
Example #26
Source File: business-page-form.js    From horondi_admin with MIT License 4 votes vote down vote up
BusinessPageForm = ({ editMode, codePath }) => {
  const dispatch = useDispatch();
  const { loading, businessPage } = useSelector(({ BusinessPages }) => ({
    loading: BusinessPages.loading,
    businessPage: BusinessPages.currentPage
  }));

  const classes = useStyles();
  const common = useCommonStyles();
  const {
    labels: { businessPageLabel },
    languages,
    businessPageErrorMessages: {
      ENTER_CODE_ERROR_MESSAGE,
      ENTER_TITLE_ERROR_MESSAGE,
      ENTER_TEXT_ERROR_MESSAGE,
      MIN_TEXT_LENGTH_MESSAGE
    },
    commonErrorMessages: {
      UA_NAME_MESSAGE,
      EN_NAME_MESSAGE,
      MIN_LENGTH_MESSAGE
    }
  } = config;

  const {
    createBusinessPage,
    createBusinessTextTranslationFields,
    uaSetText,
    enSetText,
    uaSetTitle,
    enSetTitle,
    uaText,
    enText,
    enTitle,
    uaTitle,
    code,
    setCode,
    files,
    setFiles
  } = useBusinessHandlers();

  useEffect(() => {
    codePath && dispatch(getBusinessPageByCode(codePath));
  }, [dispatch, codePath]);

  useEffect(() => {
    const isEditingReady = businessPage && editMode;

    setCode(setCodeHandler(isEditingReady, businessPage));
    uaSetTitle(uaSetTitleHandler(isEditingReady, businessPage));
    uaSetText(uaSetTextHandler(isEditingReady, businessPage));
    enSetTitle(enSetTitleHandler(isEditingReady, businessPage));
    enSetText(enSetTextHandler(isEditingReady, businessPage));
  }, [
    code,
    setCode,
    editMode,
    businessPage,
    uaSetText,
    uaSetTitle,
    enSetText,
    enSetTitle
  ]);

  const formSchema = Yup.object().shape({
    code: Yup.string()
      .matches(config.formRegExp.pageCode, ENTER_CODE_ERROR_MESSAGE)
      .required(ENTER_CODE_ERROR_MESSAGE),
    uaTitle: Yup.string()
      .min(2, MIN_LENGTH_MESSAGE)
      .matches(config.formRegExp.uaNameCreation, EN_NAME_MESSAGE)
      .required(ENTER_TITLE_ERROR_MESSAGE),
    enTitle: Yup.string()
      .min(2, MIN_LENGTH_MESSAGE)
      .matches(config.formRegExp.enNameCreation, UA_NAME_MESSAGE)
      .required(ENTER_TITLE_ERROR_MESSAGE),
    enText: Yup.string()
      .min(17, MIN_TEXT_LENGTH_MESSAGE)
      .matches(config.formRegExp.enDescription, EN_NAME_MESSAGE)
      .required(ENTER_TEXT_ERROR_MESSAGE),
    uaText: Yup.string()
      .min(17, MIN_TEXT_LENGTH_MESSAGE)
      .required(ENTER_TEXT_ERROR_MESSAGE)
  });

  const {
    values,
    errors,
    touched,
    handleSubmit,
    handleBlur,
    handleChange,
    setFieldValue
  } = useFormik({
    initialValues: {
      code,
      uaTitle,
      enTitle,
      uaText,
      enText
    },
    validationSchema: formSchema,
    onSubmit: async () => {
      const uniqueFiles = files.filter((file, i) => {
        const { name, size } = file;
        return indexFinder(i, files, name, size);
      });

      const newUaText = values.uaText.replace(/src="data:image.*?"/g, 'src=""');
      const newEnText = values.enText.replace(/src="data:image.*?"/g, 'src=""');

      const page = createBusinessPage(values);

      const businessTextTranslationFields = createBusinessTextTranslationFields(
        {
          ...values,
          uaText: newUaText,
          enText: newEnText
        }
      );

      businessPageDispatchHandler(
        editMode,
        dispatch,
        updateBusinessPage,
        addBusinessPage,
        {
          id: businessPage._id,
          page,
          businessTextTranslationFields,
          files: uniqueFiles
        },
        { page, files: uniqueFiles }
      );
    }
  });

  const changed = useChangedValuesChecker(values, errors);
  const unblock = useUnsavedChangesHandler(values);

  useMemo(() => {
    values.code = code;
    values.uaTitle = uaTitle;
    values.enTitle = enTitle;
    values.uaText = uaText;
    values.enText = enText;
  }, [code, uaTitle, enTitle, uaText, enText]);

  if (loading) {
    return <LoadingBar />;
  }

  businessPageLabel[1].setFiles = setFiles;

  const inputOptions = {
    errors,
    touched,
    handleChange,
    handleBlur,
    values,
    inputs: businessPageLabel,
    setFieldValue
  };

  const eventPreventHandler = (e) => {
    e.preventDefault();
  };

  return (
    <div className={classes.container}>
      <div className={classes.buttonContainer}>
        <Grid container spacing={2} className={classes.fixedButtons}>
          <Grid item className={classes.button}>
            <SaveButton
              id='save'
              type='submit'
              title='Зберегти'
              data-cy='save-btn'
              onClickHandler={handleSubmit}
              unblockFunction={unblock}
              values={{
                code: values.code,
                uaTitle: values.uaTitle,
                enTitle: values.enTitle
              }}
              errors={errors}
              {...(businessPage?._id ? { disabled: !changed } : {})}
            />
          </Grid>
        </Grid>
      </div>
      <div className={common.adminHeader}>
        <Typography
          variant='h1'
          className={common.materialTitle}
          data-cy='add-header'
        >
          {config.titles.businessPageTitles.addBusinessPageTitle}
        </Typography>
      </div>

      <form onSubmit={(e) => eventPreventHandler(e)}>
        <Grid item xs={12}>
          <Paper className={classes.businessPageForm}>
            <TextField
              id='code'
              className={classes.textField}
              variant='outlined'
              label='Код сторінки'
              value={values.code}
              onChange={handleChange}
              onBlur={handleBlur}
              error={touched.code && !!errors.code}
              data-cy='page-code'
            />
          </Paper>
          {touched.code && errors.code && (
            <div data-cy='code-error' className={classes.errorMessage}>
              {errors.code}
            </div>
          )}
        </Grid>
        {languages.map((lang) => (
          <LanguagePanel lang={lang} inputOptions={inputOptions} key={lang} />
        ))}
      </form>
    </div>
  );
}
Example #27
Source File: RegisterForm.js    From Django-REST-Framework-React-BoilerPlate with MIT License 4 votes vote down vote up
// ----------------------------------------------------------------------

export default function RegisterForm() {
  const dispatch = useDispatch();
  const navigate = useNavigate();

  const userLogin = useSelector((state) => state.userLogin);
  const { userInfo } = userLogin;

  const userRgister = useSelector((state) => state.userRgister);
  const { error: registerError, loading: registerLoading } = userRgister;

  const [showPassword, setShowPassword] = useState(false);

  const RegisterSchema = Yup.object().shape({
    firstName: Yup.string().min(2, 'Too Short!').max(50, 'Too Long!').required('First name required'),
    lastName: Yup.string().min(2, 'Too Short!').max(50, 'Too Long!').required('Last name required'),
    email: Yup.string().email('Email must be a valid email address').required('Email is required'),
    password: Yup.string().required('Password is required'),
  });

  const formik = useFormik({
    initialValues: {
      firstName: '',
      lastName: '',
      email: '',
      password: '',
    },
    validationSchema: RegisterSchema,
    onSubmit: () => {
      dispatch(register(values.firstName, values.lastName, values.email, values.password));
    },
  });

  const { errors, touched, values, handleSubmit, isSubmitting, getFieldProps } = formik;
  useEffect(() => {
    if (userInfo) {
      navigate('/dashboard/app', { replace: true });
    }
  }, [navigate, userInfo]);
  return (
    <FormikProvider value={formik}>
      <Form autoComplete="off" noValidate onSubmit={handleSubmit}>
        <Stack spacing={3}>
          <Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
            <TextField
              fullWidth
              label="First name"
              {...getFieldProps('firstName')}
              error={Boolean(touched.firstName && errors.firstName)}
              helperText={touched.firstName && errors.firstName}
            />

            <TextField
              fullWidth
              label="Last name"
              {...getFieldProps('lastName')}
              error={Boolean(touched.lastName && errors.lastName)}
              helperText={touched.lastName && errors.lastName}
            />
          </Stack>

          <TextField
            fullWidth
            autoComplete="username"
            type="email"
            label="Email address"
            {...getFieldProps('email')}
            error={Boolean(touched.email && errors.email)}
            helperText={touched.email && errors.email}
          />

          <TextField
            fullWidth
            autoComplete="current-password"
            type={showPassword ? 'text' : 'password'}
            label="Password"
            {...getFieldProps('password')}
            InputProps={{
              endAdornment: (
                <InputAdornment position="end">
                  <IconButton edge="end" onClick={() => setShowPassword((prev) => !prev)}>
                    <Iconify icon={showPassword ? 'eva:eye-fill' : 'eva:eye-off-fill'} />
                  </IconButton>
                </InputAdornment>
              ),
            }}
            error={Boolean(touched.password && errors.password)}
            helperText={touched.password && errors.password}
          />

          {registerError ? (
            <Alert severity="error">
              <AlertTitle>Register Error</AlertTitle>
              {registerError}
            </Alert>
          ) : null}

          <LoadingButton
            fullWidth
            size="large"
            type="submit"
            variant="contained"
            loading={registerLoading ? isSubmitting : null}
          >
            Register
          </LoadingButton>
        </Stack>
      </Form>
    </FormikProvider>
  );
}
Example #28
Source File: category-form.js    From horondi_admin with MIT License 4 votes vote down vote up
CategoryForm = ({ category, id, edit }) => {
  const styles = useStyles();
  const dispatch = useDispatch();
  const { createCategory, setUpload, upload, categoryImage, setCategoryImage } =
    useCategoryHandlers();

  const { pathToCategories } = config.routes;

  const categoryValidationSchema = Yup.object().shape({
    code: Yup.string()
      .min(2, CATEGORY_VALIDATION_ERROR)
      .max(30, CATEGORY_VALIDATION_ERROR)
      .required(ERROR_MESSAGE)
      .matches(categoryCode, CATEGORY_CODE_MESSAGE),
    uaName: Yup.string()
      .min(2, CATEGORY_VALIDATION_ERROR_CATEGORY_NAME)
      .max(50, CATEGORY_VALIDATION_ERROR_CATEGORY_NAME)
      .required(ERROR_MESSAGE)
      .matches(uaNameCreation, UA_NAME_MESSAGE),
    enName: Yup.string()
      .min(2, CATEGORY_VALIDATION_ERROR_CATEGORY_NAME)
      .max(50, CATEGORY_VALIDATION_ERROR_CATEGORY_NAME)
      .required(ERROR_MESSAGE)
      .matches(enNameCreation, EN_NAME_MESSAGE)
  });

  const {
    values,
    handleSubmit,
    handleChange,
    handleBlur,
    touched,
    errors,
    setFieldValue
  } = useFormik({
    validationSchema: categoryValidationSchema,
    initialValues: getCategoryInitialValues(edit, IMG_URL, category),
    onSubmit: (data) => {
      const newCategory = createCategory(data);
      const uploadCondition = upload instanceof File;
      onSubmitCategoryHandler(edit, dispatch, updateCategory, {
        id,
        category: newCategory,
        upload
      });
      onSubmitCategoryHandler(uploadCondition, dispatch, addCategory, {
        category: newCategory,
        upload
      });
      if (!uploadCondition && !category.images.thumbnail) {
        dispatch(showErrorSnackbar(CATEGORY_ERROR));
      }
    }
  });

  const unblock = useUnsavedChangesHandler(values);

  const handleImageLoad = (files) => {
    if (files && files[0]) {
      const reader = new FileReader();
      reader.onload = (event) => {
        setFieldValue('categoryImage', event.target.result);
        setCategoryImage(event.target.result);
      };
      reader.readAsDataURL(files[0]);
      setUpload(files[0]);
    }
  };
  const inputs = [
    { label: config.labels.categories.categoryName, name: 'name' }
  ];
  const inputOptions = {
    errors,
    touched,
    handleChange,
    handleBlur,
    values,
    inputs
  };

  const eventPreventHandler = (e) => {
    e.preventDefault();
  };

  return (
    <div>
      <form onSubmit={(e) => eventPreventHandler(e)}>
        <div className={styles.buttonContainer}>
          <Grid container spacing={2} className={styles.fixedButtons}>
            <Grid item className={styles.button}>
              <BackButton pathBack={pathToCategories} />
            </Grid>
            <Grid item className={styles.button}>
              <SaveButton
                data-cy='save'
                type={materialUiConstants.types.submit}
                title={SAVE_TITLE}
                onClickHandler={handleSubmit}
                unblockFunction={unblock}
                errors={errors}
                values={{
                  uaName: values.uaName,
                  enName: values.enName,
                  code: values.code
                }}
              />
            </Grid>
          </Grid>
        </div>
        <Grid item xs={12}>
          <Paper className={styles.categoryItemUpdate}>
            <span className={styles.imageUpload}>
              {config.labels.avatarText}
            </span>
            <div className={styles.imageUploadAvatar}>
              <ImageUploadContainer
                handler={handleImageLoad}
                src={edit ? values.categoryImage : categoryImage}
              />
            </div>
            <TextField
              data-cy='code'
              name='code'
              className={styles.textField}
              variant='outlined'
              placeholder={config.labels.categories.categoryCode}
              value={values.code}
              onChange={handleChange}
              onBlur={handleBlur}
              error={touched.code && !!errors.code}
            />
            {touched.code && errors.code && (
              <div data-cy='code-error' className={styles.error}>
                {errors.code}
              </div>
            )}
          </Paper>
        </Grid>
        {languages.map((lang) => (
          <LanguagePanel lang={lang} inputOptions={inputOptions} key={lang} />
        ))}
      </form>
    </div>
  );
}
Example #29
Source File: register.jsx    From UpStats with MIT License 4 votes vote down vote up
Register = (props) => {
  const toast = useToast();
  const register = async (creds) => {
    try {
      const { data: jwt } = await http.post("/users/create", { ...creds });
      window.localStorage.setItem(tokenKey, jwt);
      window.location = "/admin";
      toast({
        title: "Success",
        description: "Redirecting...",
        status: "success",
        duration: 9000,
        isClosable: true,
      });
    } catch (ex) {
      toast({
        title: "Error",
        description: "Cannot Login to Account",
        status: "error",
        duration: 9000,
        isClosable: true,
      });
    }
  };
  useEffect(() => {
    const token = window.localStorage.getItem("token");

    if (token) {
      window.location = "/admin";
    }
  }, []);

  const formik = useFormik({
    initialValues: {
      name: "",
      email: "",
      password: "",
    },
    validationSchema: Yup.object({
      name: Yup.string().label("Name").required(),
      email: Yup.string().email().label("Email").required(),
      password: Yup.string().label("Password").required(),
    }),
    onSubmit: (values) => {
      register(values);

      //alert(JSON.stringify(values, null, 2));
    },
  });
  return (
    <div className="w-full max-w-sm mx-auto overflow-hidden rounded-lg">
      <div className="px-6 py-4">
        <h2 className="mt-1 text-3xl font-medium text-center">Welcome Back</h2>
        <p className="mt-1 text-center">Login to continue</p>
        <form onSubmit={formik.handleSubmit}>
          <Stack>
            <Text>Name</Text>
            <Input
              id="name"
              name="name"
              type="text"
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              value={formik.values.name}
              placeholder="Enter here"
              isInvalid={
                formik.touched.name && formik.errors.name ? true : false
              }
            />
            {formik.touched.name && formik.errors.name ? (
              <Alert status="error">
                <AlertIcon />
                {formik.errors.name}
              </Alert>
            ) : null}
          </Stack>
          <Stack>
            <Text>Email</Text>
            <Input
              id="email"
              name="email"
              type="text"
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              value={formik.values.email}
              placeholder="Enter here"
              isInvalid={
                formik.touched.email && formik.errors.email ? true : false
              }
            />
            {formik.touched.email && formik.errors.email ? (
              <Alert status="error">
                <AlertIcon />
                {formik.errors.email}
              </Alert>
            ) : null}
          </Stack>
          <Stack>
            <Text>Password</Text>
            <Input
              id="password"
              name="password"
              type="password"
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
              value={formik.values.password}
              placeholder="Enter here"
              isInvalid={
                formik.touched.password && formik.errors.password ? true : false
              }
            />
            {formik.touched.password && formik.errors.password ? (
              <Alert status="error">
                <AlertIcon />
                {formik.errors.password}
              </Alert>
            ) : null}
          </Stack>
          {/* Register */}
          <div className="flex items-center  mt-4">
            <button
              style={{ backgroundColor: "#3747D4" }}
              className="px-4 py-2 text-white rounded hover:bg-black focus:outline-none"
              type="submit"
            >
              Register
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}