@apollo/react-hooks#useMutation JavaScript Examples

The following examples show how to use @apollo/react-hooks#useMutation. 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: SignIn.jsx    From saasgear with MIT License 6 votes vote down vote up
function SignIn() {
  useDocumentHeader({ title: 'Sign In' });
  const { register, handleSubmit, errors: formErrors } = useForm({
    resolver: yupResolver(SignInSchema),
  });
  const [loginMutation, { error, loading }] = useMutation(loginQuery);
  const history = useHistory();

  async function onSubmit(params) {
    try {
      const { data } = await loginMutation({ variables: params });
      if (data?.login) {
        history.push('/');
      }
    } catch (e) {
      console.log(e);
    }

    return false;
  }

  return (
    <SignUpFormWrapper>
      <SignUpFormLeft>
        <SignInForm
          onSubmit={handleSubmit(onSubmit)}
          register={register}
          formErrors={formErrors}
          apiError={error?.message}
          isSubmitting={loading}
        />
      </SignUpFormLeft>
      <SignUpAds>
        <AuthAdsArea />
      </SignUpAds>
    </SignUpFormWrapper>
  );
}
Example #2
Source File: LikeButton.js    From 0.4.1-Quarantime with MIT License 6 votes vote down vote up
function LikeButton({ user, post: { id, likeCount, likes } }) {
  const [liked, setLiked] = useState(false);

  useEffect(() => {
    if (user && likes.find((like) => like.username === user.username)) {
      setLiked(true);
    } else setLiked(false);
  }, [user, likes]);

  const [likePost] = useMutation(LIKE_POST_MUTATION, {
    variables: { postId: id }
  });

  const likeButton = user ? (
    liked ? (
      <Button color="pink" >
        <Icon name="heart" />
      </Button>
    ) : (
      <Button color="pink" basic>
        <Icon name="heart" />
      </Button>
    )
  ) : (
    <Button as={Link} to="/login" color="pink" basic>
      <Icon name="heart" />
    </Button>
  );

  return (
    <Button as="div" labelPosition="right" onClick={likePost}>
      <MyPopup content={liked ? 'Unlike' : 'Like'}>{likeButton}</MyPopup>
      <Label basic color="pink" pointing="left">
        {likeCount}
      </Label>
    </Button>
  );
}
Example #3
Source File: Admin.jsx    From saasgear with MIT License 6 votes vote down vote up
function AdminLayoutContainer() {
  const { data: userPlanData, loading: loadingUserPlan } = useQuery(
    getUserPlanQuery,
  );
  const [logout] = useMutation(logoutQuery);
  const dispatch = useDispatch();
  const history = useHistory();

  useEffect(() => {
    dispatch(
      setUserPlan({
        data: userPlanData?.getUserPlan,
        loading: loadingUserPlan,
      }),
    );
  }, [userPlanData, loadingUserPlan]);

  async function signout() {
    await logout();
    history.push('/auth/signin');
  }

  return <AdminLayout signout={signout} />;
}
Example #4
Source File: CreateProperty.js    From willow-grandstack with Apache License 2.0 6 votes vote down vote up
export default function CreateProperty() {
  let input
  const [createProperty, { data, loading, error }] = useMutation(
    CREATE_PROPERTY_MUTATION
  )

  return (
    <div>
      <form
        onSubmit={(e) => {
          e.preventDefault()
          createProperty({ variables: { city: input.value } })
          input.value = ''
        }}
      >
        <input
          ref={(n) => {
            input = n
          }}
        />
        <button type="submit">Add City</button>
      </form>
    </div>
  )
}
Example #5
Source File: ViewPost.js    From graphql-sample-apps with Apache License 2.0 5 votes vote down vote up
export default function ViewPost(props) {
  const [numLikes, setNumLikes] = useState(0);
  const history = useHistory();
  const editPost = (postID) => {
    history.push({
      pathname: '/edit',
      search: `?postID=${postID}`
    })
  }
  const postSet = {
    numLikes: numLikes +1
  }
  let params = queryString.parse(props.location.search);
  let postID = params.postID;

  const { loading, error, data } = useQuery(GET_POST, { variables: { postID }, fetchPolicy: "network-only" });
  const [deletePost] = useMutation(DELETE_POST);
  const [updatePost] = useMutation(POST_MUTATION);

  if (loading) return "Fetching Posts...";
  if (error) return `Error: ${error}`;
  const post = data.getPost;
  if (numLikes === 0) {
    setNumLikes(post.numLikes)
  }

  return (
    <div className="container">
      <div className="h3 text-center">{post.title}
      <span className="delete-post" onClick={async e => {
          e.preventDefault();
          await deletePost({ variables: { postID } })
          history.push({
            pathname: '/'
          }); 
        }}>
          <i className="icon-trash" aria-hidden="true"></i>
        </span>
        <span className="edit-post" onClick={() => editPost(post.postID)}>
          <i className="icon-edit" aria-hidden="true"></i>
        </span>
      </div>
      <hr />
      <div className="text-post">{post.text}</div>
      <div>
        <button type="button" className="btn btn-primary btn-sm" onClick = { async e => {
          e.preventDefault()
          await updatePost({ variables: { postSet, postID} })
          history.push({
            pathname: '/',
          }); 
          history.push({
            pathname: '/view',
            search: `?postID=${postID}`
          });
        }}>
          Likes <span className="badge badge-light">{post.numLikes}</span>
        </button>
        <span className="tagsset-post">
          {post.tags.map(tag => (
            <span
              className="badge badge-secondary tag-post"
              key={tag}
            >
              {tag}
            </span>
          ))}
        </span>
      </div>
    </div>
  );
}
Example #6
Source File: Step1.jsx    From dineforward with MIT License 5 votes vote down vote up
OnboardingStep1 = ({ classes = {}, forward, setBusinessId }) => {
  const userId = useIdentity()?.id;
  if (!userId) throw new Error(`Unable to get authenticated user information`);

  const [createBiz, { loading, error }] = useMutation(CREATE_BIZ_AND_UPDATE_USER, {
    onCompleted: data => {
      console.log(`createbiz completed`, data);
      const id = data?.createBusiness?.id;
      if (!id) throw new Error(`Did not receive new business ID back from API`);
      setBusinessId(id);
      forward();
    },
    // Must provide onError to avoid unhandled Promise rejection
    onError: err => {},
  });

  const onSubmit = (formData, { setSubmitting }) => {
    let { contactPhone, ...bizData } = formData;
    bizData = removeEmpty(bizData);
    const userData = removeEmpty({ contactPhone });

    if (!loading) {
      createBiz({
        variables: {
          bizData,
          uid: userId,
          userData,
        },
      })
        // Restore submit button
        .then(() => setSubmitting(false));
    }
  };

  const errorMsg = getErrorMsg(error);

  return (
    <Grid container spacing={5} className={classes.root} direction="column" alignItems="center">
      {errorMsg && (
        <Grid item md={12}>
          <Alert severity="error">{errorMsg}</Alert>
        </Grid>
      )}
      <Grid item md={8} xs={12}>
        <Typography
          className={classes.stepTitle}
          variant="subtitle1"
        >
          {stepTitle}
        </Typography>
        <ComplexFormBuilder
          schema={requestBizForm.form}
          formAction={onSubmit}
          >
          {({ isSubmitting }) => (
            <div>
              <p>* Required items</p>
              <Box display="flex" justifyContent="flex-end" className={classes.buttonBox}>
                <Button
                  type="submit"
                  variant="contained"
                  color="primary"
                  disabled={isSubmitting}
                  endIcon={<DoubleArrow />}
                >
                  Next
                </Button>
              </Box>
            </div>
          )}
        </ComplexFormBuilder>
      </Grid>
    </Grid>
  );
}
Example #7
Source File: App.js    From todo-react-graphql with MIT License 5 votes vote down vote up
function App() {
  let input;
  const { data, loading, error } = useQuery(READ_TODOS);
  const [createTodo] = useMutation(CREATE_TODO);
  const [deleteTodo] = useMutation(REMOVE_TODO);
  const [updateTodo] = useMutation(UPDATE_TODO);

  if (loading) return <p>loading...</p>;
  if (error) return <p>ERROR</p>;
  if (!data) return <p>Not found</p>;

  return (
    <div className="app">
      <h3>Create New Todo</h3>
      <form onSubmit={e => {
        e.preventDefault();
        createTodo({ variables: { text: input.value } });
        input.value = '';
        window.location.reload();
      }}>
        <input className="form-control" type="text" placeholder="Enter todo" ref={node => { input = node; }}></input>
        <button className="btn btn-primary px-5 my-2" type="submit">Submit</button>
      </form>
      <ul>
        {data.todos.map((todo) =>
          <li key={todo.id} className="w-100">
            <span className={todo.completed ? "done" : "pending"}>{todo.text}</span>
            <button className="btn btn-sm btn-danger rounded-circle float-right" onClick={() => {
              deleteTodo({ variables: { id: todo.id } });
              window.location.reload();
            }}>X</button>
            <button className={`btn btn-sm float-right ${todo.completed ? "btn-success" : "btn-info"}`} onClick={() => {
              updateTodo({ variables: { id: todo.id } });
              window.location.reload();
            }}>{todo.completed ? <span>Completed</span> : <span>Not completed</span>}</button>
          </li>
        )}
      </ul>
    </div>
  );
}
Example #8
Source File: Login.js    From 0.4.1-Quarantime with MIT License 5 votes vote down vote up
function Login(props) {
  const context = useContext(AuthContext);
  const [errors, setErrors] = useState({});

  const { onChange, onSubmit, values } = useForm(loginUserCallback, {
    username: '',
    password: ''
  });

  const [loginUser, { loading }] = useMutation(LOGIN_USER, {
    update(
      _,
      {
        data: { login: userData }
      }
    ) {
      context.login(userData);
      props.history.push('/');
    },
    onError(err) {
      setErrors(err.graphQLErrors[0].extensions.exception.errors);
    },
    variables: values
  });

  function loginUserCallback() {
    loginUser();
  }

  return (
    <div className="form-container">
      <Form onSubmit={onSubmit} noValidate className={loading ? 'loading' : ''}>
        <h1>Login</h1>
        <Form.Input
          label="Username"
          placeholder="Username.."
          name="username"
          type="text"
          value={values.username}
          error={errors.username ? true : false}
          onChange={onChange}
        />
        <Form.Input
          label="Password"
          placeholder="Password.."
          name="password"
          type="password"
          value={values.password}
          error={errors.password ? true : false}
          onChange={onChange}
        />
        <Button type="submit" primary>
          Login
        </Button>
      </Form>
      {Object.keys(errors).length > 0 && (
        <div className="ui error message">
          <ul className="list">
            {Object.values(errors).map((value) => (
              <li key={value}>{value}</li>
            ))}
          </ul>
        </div>
      )}
    </div>
  );
}
Example #9
Source File: CreateQuestion.js    From graphql-sample-apps with Apache License 2.0 5 votes vote down vote up
export default function CreateQuestion(props) {
  const [title, setTitle] = useState("");
  const [text, setText] = useState("");
  const [tags, setTags] = useState([])

  const history = useHistory();
  const { user } = useAuth0();
  let currentUser
  if (user !== undefined) {
    currentUser = {"username": user.email, "email": user.email}
  }

  const question = [{
    title,
    text,
    tags,
    author: currentUser,
    datePublished: new Date().toISOString(),
    likes: 0
  }];

  const handleChangeTags = (tagsSet) => {
    setTags(tagsSet)
  }

  const [addQuestion] = useMutation(ADD_QUESTION)

  return (
    <div className="container">
      <hr />
      <div className="form-group">
        <label htmlFor="questionTitle">Title:</label>
        <input
          id="questionTitle"
          className="form-control"
          value={title}
          onChange={e => setTitle(e.target.value)}
          type="text"
          placeholder="Add Title"
        />
      </div>
      <div className="form-group">
        <label htmlFor="questionTags">Tags:</label>
        <TagsInput value={tags} onChange={handleChangeTags} />
      </div>
      <div className="form-group">
        <label htmlFor="questionText">Text:</label>
        <textarea
          id="questionText"
          className="form-control"
          rows="15"
          cols="100"
          value={text}
          onChange={e => setText(e.target.value)}
          type="text"
          placeholder="Add your question text"
        />
      </div>
          <button
              type="submit"
              className="btn btn-primary"
              onClick={async e => {
                e.preventDefault();
                await addQuestion({ variables: {question}})
                history.push("/");
              }}
          >
            Publish
          </button>
    </div>
  );
}
Example #10
Source File: EmailVerification.js    From lifebank with MIT License 5 votes vote down vote up
EmailVerification = (props) => {
  const { t } = useTranslation('translations')
  const classes = useStyles()
  const [, { logout }] = useUser()
  const [validate, setValidate] = useState(true)
  const { code } = useParams()
  const history = useHistory()

  const [
    verifyEmail,
    { loading: loadingVerifyEmail, error: errorVerifyEmail, data: { verify_email: verifyEmailResult } = {} }
  ] = useMutation(VERIFY_EMAIL)

  useEffect(() => {
    verifyEmail({
      variables: {
        code: code
      }
    })
  }, [verifyEmail, code])

  useEffect(() => {
    if (verifyEmailResult) setValidate(verifyEmailResult.is_verified)

  }, [verifyEmailResult])

  useEffect(() => {
    if (errorVerifyEmail) {
      if (errorVerifyEmail.message === 'GraphQL error: Could not verify JWT: JWTExpired') {
        logout()
        verifyEmail({
          variables: {
            code: code
          }
        })
      } else {
        setValidate(false)
        history.push('/internal-error')
      }
    }

  }, [verifyEmail, logout, code, history, errorVerifyEmail])

  return (
    <Box className={classes.root}>
      <Grid container spacing={4}>
        <Grid item xs={12} className={classes.content}>
          <Box className={classes.centerText}>
            {loadingVerifyEmail && <CircularProgress />}
            {!loadingVerifyEmail && validate && (
              <Typography className={classes.title}>
                {t('emailVerification.emailVerified')}
              </Typography>
            )}
            {!loadingVerifyEmail && !validate && (
              <Typography className={classes.title}>
                {t('emailVerification.somethingHappened')}
              </Typography>
            )}
            {!loadingVerifyEmail && (
              <Button
                variant="contained"
                color="secondary"
                component={CustomRouterLink}
                to="/"
                className={classes.btnHome}
              >
                {t('emailVerification.takeHome')}
              </Button>
            )}
          </Box>
        </Grid>
      </Grid>
    </Box>
  )
}
Example #11
Source File: DeleteButton.js    From 0.4.1-Quarantime with MIT License 5 votes vote down vote up
function DeleteButton({ postId, commentId, callback }) {
  const [confirmOpen, setConfirmOpen] = useState(false);

  const mutation = commentId ? DELETE_COMMENT_MUTATION : DELETE_POST_MUTATION;

  const [deletePostOrMutation] = useMutation(mutation, {
    update(proxy) {
      setConfirmOpen(false);
      if (!commentId) {
        const data = proxy.readQuery({
          query: FETCH_POSTS_QUERY
        });
        data.getPosts = data.getPosts.filter((p) => p.id !== postId);
        proxy.writeQuery({ query: FETCH_POSTS_QUERY, data });
      }
      if (callback) callback();
    },
    variables: {
      postId,
      commentId
    }
  });
  return (
    <>
      <MyPopup content={commentId ? 'Delete comment' : 'Delete post'}>
        <Button
          as="div"
          color="red"
          floated="right"
          onClick={() => setConfirmOpen(true)}
        >
          <Icon name="trash" style={{ margin: 0 }} />
        </Button>
      </MyPopup>
      <Confirm
        open={confirmOpen}
        onCancel={() => setConfirmOpen(false)}
        onConfirm={deletePostOrMutation}
      />
    </>
  );
}
Example #12
Source File: CancelEmailSubscription.js    From lifebank with MIT License 5 votes vote down vote up
CancelEmailSubscription = () => {
  const { t } = useTranslation('translations')
  const classes = useStyles()
  const { account } = useParams()
  const [openSnackbar, setOpenSnackbar] = useState(false)

  const handleOpenSnackbar = () => {
    setOpenSnackbar(!openSnackbar)
  }

  const [
    updateEmailSubscription,
    {
      loading: updateEmailSubscriptionLoading,
      data: { update_user: updateEmailSubscriptionResult } = {}
    }
  ] = useMutation(UPDATE_EMAIL_SUBSCRIPTION_MUTATION)

  const onUpdateEmailSubscriptionClick = () => {
    updateEmailSubscription({
      variables: {
        account,
        state: false
      }
    })
  }

  useEffect(() => {
    if (updateEmailSubscriptionResult && updateEmailSubscriptionResult.affected_rows === 0) handleOpenSnackbar()
  }, [handleOpenSnackbar, updateEmailSubscriptionResult])

  return (
    <Box className={classes.root}>
      <Grid container spacing={4}>
        <Grid item xs={12} className={classes.content}>
          <Box className={classes.centerText}>
            {updateEmailSubscriptionLoading && <CircularProgress />}
            {!updateEmailSubscriptionLoading && !updateEmailSubscriptionResult && (
              <Typography className={classes.title}>
                {t('emailSubscription.cancelMessage')}
              </Typography>
            )}
            {!updateEmailSubscriptionLoading && updateEmailSubscriptionResult && (
              <Typography className={classes.title}>
                {t('emailSubscription.successfulCancel')}
              </Typography>
            )}
            {!updateEmailSubscriptionLoading && !updateEmailSubscriptionResult && (
              <Button
                variant="contained"
                color="secondary"
                onClick={onUpdateEmailSubscriptionClick}
                className={classes.btnHome}
              >
                {t('emailSubscription.cancel')}
              </Button>
            )}
            {!updateEmailSubscriptionLoading && updateEmailSubscriptionResult && (
              <Button
                variant="contained"
                color="secondary"
                component={CustomRouterLink}
                to="/"
                className={classes.btnHome}
              >
                {t('emailVerification.takeHome')}
              </Button>
            )}
          </Box>
        </Grid>
      </Grid>
      <Snackbar open={openSnackbar} autoHideDuration={4000} onClose={handleOpenSnackbar}>
        <Alert severity="error">
          {t('emailSubscription.error')}
        </Alert>
      </Snackbar>
    </Box>
  )
}
Example #13
Source File: DetailPage.js    From mongodb-graphql-demo with Apache License 2.0 5 votes vote down vote up
function DetailPage(props) {
	const [deletePost] = useMutation(DELETE_INSTAPOST);
	const { instapost } = props;

	return (
		<Modal
			isOpen
			ariaHideApp={false}
			contentLabel="Create Post"
			style={detailModalStyle}
			onRequestClose={props.history.goBack}
		>
			<div
				className="close fixed right-0 top-0 pointer"
				onClick={props.history.goBack}
			>
				<img src={require('../assets/close.svg')} alt="" />
			</div>
			<div
				className="delete ttu white pointer fw6 absolute left-0 top-0 br2"
				onClick={e => {
					deletePost({
						variables: {
							data: {
								_id: instapost._id,
							},
						},
					});
					props.history.replace('/');
				}}
			>
				Delete
			</div>
			<div className="bg-white detail flex flex-column no-underline br2 h-100">
				<div
					className="image"
					style={{
						backgroundImage: `url(${instapost.imageUrl})`,
						backgroundSize: 'cover',
						backgroundPosition: 'center',
						paddingBottom: '100%',
					}}
				/>
				<div className="flex items-center black-80 fw3 description">
					{instapost.description}
				</div>
			</div>
		</Modal>
	);
}
Example #14
Source File: GithubAuth.js    From pathways with GNU General Public License v3.0 5 votes vote down vote up
GithubAuth = (props) => {

    const [isTouched, isTouchedHandler] = useState(false);
    const [getToken, { loading, data }] = useMutation(GET_TOKEN);

    let display = <Container>
        <Header>
            <div style={{ display: "flex", alignItems: "center" }}>
                <Logo />
                <Logotype />
            </div>
            <a href={`https://github.com/login/oauth/authorize?client_id=${CLIENT_ID}&scope=user`}>
                Login
            </a>
        </Header>
    </Container>

    let displayedData = null;
    let code = null;
    code = decodeURIComponent(window.location.search.replace(new RegExp("^(?:.*[&\\?]" + encodeURIComponent('code').replace(/[\.\+\*]/g, "\\$&") + "(?:\\=([^&]*))?)?.*$", "i"), "$1"));
    if (code && !isTouched) {
        isTouchedHandler(true);
        getToken({ variables: { code: code } })
    }

    if(!isTouched){
        displayedData = null;
    }
    else{
        if (loading) {
            displayedData = <div>Loading ...</div>
        }
        else {
            let token = data.GithubAuth.token;
            displayedData = <div>Your Token is <br />{token}</div>
        }
    }

    return (
        <div>
            {display}
            <div>{displayedData}</div>
        </div>
    );
}
Example #15
Source File: NotificationStructure.js    From lifebank with MIT License 5 votes vote down vote up
NotificationStructure = ({ id, title, description, state, dateAndTime }) => {
  const classes = useStyles()
  const [name, setName] = useState()
  const [time, setTime] = useState()

  const { refetch: getData } = useQuery(GET_ACCOUNT_NAME, {
    variables: {
      account: description.substring(5, 17)
    },
    skip: true
  })

  const [editNotificationState, { }] = useMutation(EDIT_NOTIFICATION_STATE)

  useEffect(() => {
    const response = async () => {
      const { data } = await getData({ account: description.substring(5, 17) })
      setName(data.user[0].name)
    }
    response()
  }, [description])

  useEffect(() => {
    const hour = parseInt(dateAndTime.substring(11, 13)) - 6
    setTime(hour.toString() + dateAndTime.substring(13, 19))
  }, [dateAndTime])

  const changeNotificationState = () => {
    editNotificationState({
      variables: {
        id: id
      }
    })
  }

  return (
    <>
      <Button className={classes.wrapper} onMouseOver={changeNotificationState}>
        <Grid container xs={3}>
          <Grid item xs={12}>
            {state === true && (
              <NewNotificationIcon className={classes.iconOption} />
            )}
          </Grid>
        </Grid>
        <Grid container xs={11}>
          <Grid item xs={12}>
            <Typography className={classes.title}>
              {title}
            </Typography>
          </Grid>
          <Grid item xs={10}>
            <Typography className={classes.labelOption}>
              {description.replace(description.substring(5, 17), name)}
            </Typography>
          </Grid>
        </Grid>
        <Grid container xs={6}>
          <Grid item xs={12}>
            <Typography className={classes.labelOption}>
              {time}
              <br ></br>
              {dateAndTime.substring(5, 10) + "-" + dateAndTime.substring(0, 4)}
            </Typography>
          </Grid>
        </Grid>
      </Button>
    </>
  )
}
Example #16
Source File: Header.js    From pathways with GNU General Public License v3.0 5 votes vote down vote up
Header = (props) => {
    const [isLoggedIn, isLoggedInHandler] = useState(false)
    const [isTouched, isTouchedHandler] = useState(false)
    const [getToken, { loading, data }] = useMutation(GET_TOKEN)

    let code = null
    code = decodeURIComponent(
        window.location.search.replace(
            new RegExp(
                "^(?:.*[&\\?]" +
                    encodeURIComponent("code").replace(/[\.\+\*]/g, "\\$&") +
                    "(?:\\=([^&]*))?)?.*$",
                "i"
            ),
            "$1"
        )
    )

    let token

    if (code && !isLoggedIn) {
        console.log(code);
        isLoggedInHandler(true)
        getToken({ variables: { code: code } })
    }

    if (data && !isTouched) {
        isTouchedHandler(true)
        token = data.GithubAuth.token
        console.log(token, data);
        props.userLogin(null);
        localStorage.setItem("token", token)
        alert("You are logged in !!!")
    }

    return (
        <React.Fragment>
            <Navbar className={classes.navbar}>
                <Nav className={classes.navlinks}>
                    <Nav.Link
                        href={`https://github.com/login/oauth/authorize?client_id=${CLIENT_ID}&scope=user`}
                    >
                        <div className={classes.login}>
                            <LogoGithub fontSize="35px" color="white" />
                            <div className={classes.text}>
                                Login with GitHub
                            </div>
                        </div>
                    </Nav.Link>
                </Nav>
            </Navbar>
        </React.Fragment>
    )
}
Example #17
Source File: ForgotPassword.jsx    From saasgear with MIT License 5 votes vote down vote up
function ForgotPassword() {
  useDocumentHeader({ title: 'Forgot password' });

  const [isSubmitted, setIsSubmitted] = useState(false);
  const { register, handleSubmit, errors } = useForm({
    resolver: yupResolver(ForgotPasswordSchema),
  });
  const [forgotPasswordMutation, { loading, error }] = useMutation(
    forgotpasswordQuery,
  );

  async function onSubmit(data) {
    setIsSubmitted(false);
    try {
      await forgotPasswordMutation({ variables: data });
      setIsSubmitted(true);
    } catch (e) {
      console.log(e);
      setIsSubmitted(false);
    }
  }

  return (
    <ForgotPasswordWrapper>
      <Overlay />
      <ForgotPasswordContainer>
        <ForgotPasswordForm
          onSubmit={handleSubmit(onSubmit)}
          register={register}
          errors={errors}
          isSubmitted={isSubmitted && !error}
          isSubmitting={loading}
          apiError={error?.message}
        />
        <SquareIconTop>
          <img src={squareRadiusTop} alt="" />
        </SquareIconTop>
        <SmallSquareBottom>
          <img src={squareRadiusTopPrimary} alt="" />
        </SmallSquareBottom>
        <SmallSquareTop>
          <img src={squareRadiusTopPrimarySmall} alt="" />
        </SmallSquareTop>
        <SmallSquareGrid>
          <img src={squareGrid} alt="" />
        </SmallSquareGrid>
        <SquareIconBottom>
          <img src={squareRadiusTopBig} alt="" />
        </SquareIconBottom>
        <CircleIcon>
          <img src={circleSmall} alt="" />
        </CircleIcon>
      </ForgotPasswordContainer>
    </ForgotPasswordWrapper>
  );
}
Example #18
Source File: TodoApp.js    From graphql-sample-apps with Apache License 2.0 4 votes vote down vote up
export default function TodoApp() {
  const [nowShowing, setNowShowing] = useState(defs.ALL_TODOS);
  const [getEditing, setEditing] = useState(null);
  const [newTodo, setNewTodo] = useState("");
  const [addTodo] = useMutation(ADD_TODO);
  const [toggleTodo] = useMutation(TOGGLE_TODO);
  const [toggleAllTodo] = useMutation(TOGGLE_ALL_TODO);
  const [deleteTodo] = useMutation(DELETE_TODO);
  const [updateTodo] = useMutation(UPDATE_TODO);
  const [clearCompletedTodo] = useMutation(CLEAR_COMPLETED_TODO);
  const [shownTodos, setShownTodos] = useState([]);

  const { loading, error, data } = useQuery(GET_TODOS);

  const getData = () => {
    if (loading || !data) {
      return null
    }
    if (error) {
      alert(`Error: ${error}`);
      return `Error: ${error.message}`;
    }

    setShownTodos(data.queryTask)
  }

  useEffect(() => {
    const setNowShowingFn = nowShowing => () => setNowShowing(nowShowing)
    const routes = {
      '/': setNowShowingFn(defs.ALL_TODOS),
      '/active': setNowShowingFn(defs.ACTIVE_TODOS),
      '/completed': setNowShowingFn(defs.COMPLETED_TODOS),
    }
    const processLocationHash = hash => {
      if (hash) {
        hash = hash.substring(1)
      }
      const route = routes[hash] || routes['/']
      route()
    }
    processLocationHash(history.location.hash)
    history.listen((location, action) =>
      processLocationHash(location.hash)
    )
    getData()
  })

 
  const handleChange = event => {
    setNewTodo(event.target.value)
  }

  const handleNewTodoKeyDown = event => {
    if (event.keyCode !== ENTER_KEY) {
      return
    }
    event.preventDefault()
    const val = newTodo
    if (val) {
      add(val)
      setNewTodo('')
    }
  }

  const add = async (title) => {
    await addTodo({
      variables: { task: [
        { title: title, completed: false }
      ]},
      refetchQueries: [{
        query: GET_TODOS
      }]
    });
  }

  const destroy = todo =>
    deleteTodo({
      variables: {
        taskID: [todo.id]
      },
      refetchQueries: [{
        query: GET_TODOS
      }]
    })

  const toggleAll = event => {
    const checked = event.target.checked
    toggleAllTodo({
      variables: {
        completed: checked
      },
      refetchQueries: [{
        query: GET_TODOS
      }]
    })
  }

  const toggle = todoToToggle => {
    toggleTodo({
      variables: {
        taskID: todoToToggle.id,
        completed: !todoToToggle.completed
      },
      refetchQueries: [{
        query: GET_TODOS
      }]
    })
  }

  const edit = todo => setEditing(todo.id)

  const save = (todoToSave, text) => {
    updateTodo({
      variables: {
        taskID: todoToSave.id,
        task: {
          title: text
        },
        refetchQueries: [{
          query: GET_TODOS
        }]
      }
    })
    setEditing(null)
  }

  const cancel = () =>
    setEditing(null)

  const clearCompleted = () =>
    clearCompletedTodo({
      variables: {
        completed: true
      },
      refetchQueries: [{
        query: GET_TODOS
      }]
    })

  const newTodos = shownTodos.filter(todo => {
    switch (nowShowing) {
      case defs.ACTIVE_TODOS:
        return !todo.completed
      case defs.COMPLETED_TODOS:
        return todo.completed
      default:
        return true
    }
  })

  const todoItems = newTodos.map(todo => {
    return (
      <TodoItem
        key={todo.id}
        todo={todo}
        onToggle={() => toggle(todo)}
        onDestroy={() => destroy(todo)}
        onEdit={() => edit(todo)}
        editing={getEditing === todo.id}
        onSave={text => save(todo, text)}
        onCancel={cancel}
      />
    )
  })

  const activeTodoCount = shownTodos.reduce(function (accum, todo) {
    return todo.completed ? accum : accum + 1
  }, 0)

  const completedCount = shownTodos.length - activeTodoCount

  const footer = (activeTodoCount || completedCount)
    ? <TodoFooter
        count={activeTodoCount}
        completedCount={completedCount}
        nowShowing={nowShowing}
        onClearCompleted={clearCompleted}
      />
    : null

  const main = !shownTodos.length
    ? null
    : (
      <section className="main">
        <input
          id="toggle-all"
          className="toggle-all"
          type="checkbox"
          onChange={toggleAll}
          checked={activeTodoCount === 0}
        />
        <label
          htmlFor="toggle-all"
        />
        <ul className="todo-list">
          {todoItems}
        </ul>
      </section>
    )

  return (
    <div>
      <header className="header">
        <h1>todos</h1>
        <input
          className="new-todo"
          placeholder="What needs to be done?"
          value={newTodo}
          onKeyDown={handleNewTodoKeyDown}
          onChange={handleChange}
          autoFocus={true}
        />
      </header>
      {main}
      {footer}
    </div>
  )
}
Example #19
Source File: PodWithdrawPendingForm.jsx    From pods-frontend with MIT License 4 votes vote down vote up
export function PodWithdrawPendingForm({ podAddress, userAddress }) {
  const [
    amount,
    setAmount
  ] = useState('')

  const [
    lastRefetchTxId,
    setLastRefetchTxId
  ] = useState(0)

  const weiAmount = ethers.utils.parseEther(amount || '0')

  let podUser = useQuery(podUserQuery, {
    variables: { podAddress, userAddress },
    skip: !userAddress || !podAddress
  })

  let transactions = useQuery(transactionsQuery)

  let loading = podUser.loading || transactions.loading
  let error = podUser.error || transactions.error

  const [withdrawPending, withdrawPendingResult] = useMutation(gql`
    mutation withdrawPendingMutation($podAddress: String!, $amount: Float!) {
      sendTransaction(abi: "Pod", address: $podAddress, fn: "withdrawPendingDeposit", params: [$amount, "0x0"], gasLimit: 800000) @client
    }
  `, {
    variables: {
      podAddress,
      amount: weiAmount
    },
    refetchQueries: ['transactionsQuery']
  })

  let withdrawPendingTx
  if (!loading && !error && withdrawPendingResult.data) {
    withdrawPendingTx = transactions.data._transactions.find(tx => tx.id === withdrawPendingResult.data.sendTransaction.id)
  }

  if (withdrawPendingTx && withdrawPendingTx.completed && withdrawPendingTx.id > lastRefetchTxId) {
    setAmount(0)
    podUser.refetch()
    setLastRefetchTxId(withdrawPendingTx.id)
  }

  let sufficientBalance = false

  if (!loading && !error && podUser.data) {
    sufficientBalance = podUser.data.pendingDeposit.gte(ethers.utils.bigNumberify(weiAmount))
  }

  return (
    <form className="w-full max-w-sm mt-5" onSubmit={(e) => { e.preventDefault(); withdrawPending(); } }>
      <div className="md:flex md:items-center mb-3">
        <div className="md:w-1/3">
          <label className="block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4" htmlFor="inline-full-name">
            Withdraw Pending Deposit
          </label>
        </div>
        <div className="md:w-2/3">
          <input
            className="bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white focus:border-purple-500"
            id="inline-full-name"
            type="text"
            placeholder="enter Dai amount"
            value={amount}
            onChange={(e) => { e.preventDefault(); setAmount(e.target.value) } }
            />
        </div>
      </div>
      <div className="md:flex md:items-center">
        <div className="md:w-1/3"></div>
        <div className="md:w-2/3">
          <Button
            disabled={!sufficientBalance}
            onClick={(e) => { e.preventDefault(); withdrawPending(); } }>
            Withdraw Pending
          </Button>
        </div>
      </div>
    </form>
  )
}
Example #20
Source File: Signup.js    From lifebank with MIT License 4 votes vote down vote up
Signup = ({ isHome, isModal, isSideBar, onCloseSignUp }) => {
  const { t } = useTranslation('translations')
  const classes = useStyles()
  const [user, setUser] = useReducer(
    (user, newUser) => ({ ...user, ...newUser }),
    {}
  )
  const [activeStep, setActiveStep] = useState(0)
  const [role, setRole] = useState()
  const [currentUser, { login }] = useUser()
  const [open, setOpen] = useState(!!isModal)
  const [openSnackbar, setOpenSnackbar] = useState(false)
  const [maxWidth] = useState('md')
  const theme = useTheme()
  const fullScreen = useMediaQuery(theme.breakpoints.down('sm'))
  const [isEmailValid, setEmailValid] = useState(false)
  const [checkEmailLoading, setcheckEmailLoaded] = useState(false)

  const handleOpen = () => {
    setOpen(!open)
    if (onCloseSignUp) {
      onCloseSignUp()
    }
  }

  const handleOpenAlert = () => {
    setOpenSnackbar({ ...openSnackbar, show: false })
  }

  const [
    createAccount,
    {
      error: errorcreateAccount,
      loading: createAccountLoading,
      data: { create_account: createAccountResult } = {}
    }
  ] = useMutation(CREATE_ACCOUNT_MUTATION)

  const [
    createAccountAuth,
    {
      error: errorcreateAccountAuth,
      loading: createAccountLoadingAuth,
      data: { create_account_auth: createAccountResultAuth } = {}
    }
  ] = useMutation(CREATE_ACCOUNT_AUTH_MUTATION)

  const [
    preRegisterLifebank,
    {
      error: errorpreRegisterLifebank,
      loading: preRegisterLifebankLoading,
      data: { create_pre_register_lifebank: preRegisterLifebankResult } = {}
    }
  ] = useMutation(CREATE_PRE_REGITER_LIFEBANK_MUTATION)

  const handleRoleChange = (role) => {
    setRole(role)
    setActiveStep(activeStep + 1)
  }

  const handleSetField = useCallback((field, value) => {
    setUser({ [field]: value })
  }, [])

  const handleGoBack = () => {
    activeStep && setActiveStep(activeStep - 1)
    handleSetField('email', ' ')
  }

  const handleCreateAccount = () => {
    const { email, name, passwordPlainText } = user
    createAccount({
      variables: {
        role,
        email,
        emailContent: {
          subject: t('emailMessage.subjectVerificationCode'),
          title: t('emailMessage.titleVerificationCode'),
          message: t('emailMessage.messageVerificationCode'),
          button: t('emailMessage.verifyButton')
        },
        name: name || t('signup.defaultUsername'),
        passwordPlainText,
        signup_method: 'lifebank'
      }
    })
  }

  const handleCreateAccountWithAuth = async (status, email, name, passwordPlainText, signupMethod) => {
    if (status) {
      const { data } = await checkEmail({ email: email })

      if (data.user.length === 0) {
        createAccountAuth({
          variables: {
            role,
            email,
            emailContent: {
              subject: t('emailMessage.subjectVerificationCode'),
              title: t('emailMessage.titleVerificationCode'),
              message: t('emailMessage.messageVerificationCode'),
              button: t('emailMessage.verifyButton')
            },
            name,
            passwordPlainText,
            signup_method: signupMethod
          }
        })
      } else {
        setOpenSnackbar({
          show: true,
          message: t('errors.authError'),
          severity: 'error'
        })
      }
    }
  }

  const handlePreRegisterLifebank = () => {
    const {
      email,
      password,
      name,
      address,
      phone,
      description,
      coordinates,
      requirement
    } = user
    let { immunity_test, invitation_code, urgency_level } = user

    if (immunity_test === undefined) immunity_test = false

    if (invitation_code === undefined || !invitation_code) invitation_code = ' '

    if (urgency_level === undefined) urgency_level = 1

    const schedule = '[]'

    preRegisterLifebank({
      variables: {
        email,
        emailContent: {
          subject: t('emailMessage.subjectVerificationCode'),
          title: t('emailMessage.titleVerificationCode'),
          message: t('emailMessage.messageVerificationCode'),
          button: t('emailMessage.verifyButton')
        },
        passwordPlainText: password,
        name,
        address,
        schedule,
        phone,
        description,
        urgency_level,
        coordinates,
        immunity_test,
        invitation_code,
        requirement
      }
    })
  }

  const { refetch: checkEmail } = useQuery(VALIDATION_EMAIL, {
    variables: {
      email: user.email
    },
    skip: true
  })

  useEffect(() => {
    const regularExpresion = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/
    const validEmail = async () => {
      const { data } = await checkEmail({
        email: user.email
      })

      if (data) {
        data.preregister_lifebank.length === 0 && data.user.length === 0
          ? setEmailValid(true)
          : setEmailValid(false)

        setcheckEmailLoaded(true)
      }
    }

    if (regularExpresion.test(user?.email)) {
      validEmail()
    } else {
      setEmailValid(false)
      setcheckEmailLoaded(false)
    }
  }, [user, checkEmail])

  useEffect(() => {
    if (preRegisterLifebankResult) {
      handleOpen()
      setOpenSnackbar({
        show: true,
        message: t('signup.sucessfulPreregistration'),
        severity: 'success'
      })

    }
  }, [t, preRegisterLifebankResult])

  useEffect(() => {
    if (createAccountResult) {
      handleOpen()
      setOpenSnackbar({
        show: true,
        message: t('signup.sucessfulRegistration'),
        severity: 'success'
      })
    }

  }, [t, createAccountResult])

  useEffect(() => {
    if (createAccountResultAuth) {
      handleOpen()
      setOpenSnackbar({
        show: true,
        message: t('signup.sucessfulRegistration'),
        severity: 'success'
      })
      login(createAccountResultAuth.token)
    }

  }, [t, login, createAccountResultAuth])


  useEffect(() => {
    if (errorcreateAccount) setOpenSnackbar({
      show: true,
      message: t('errors.authError'),
      severity: 'error'
    })

  }, [t, errorcreateAccount])

  useEffect(() => {
    if (errorcreateAccountAuth) setOpenSnackbar({
      show: true,
      message: t('errors.authError'),
      severity: 'error'
    })
  }, [t, errorcreateAccountAuth])

  useEffect(() => {
    if (errorpreRegisterLifebank) setOpenSnackbar({
      show: true,
      message: t('errors.authError'),
      severity: 'error'
    })

  }, [t, errorpreRegisterLifebank])

  useEffect(() => {
    if (open) {
      handleSetField('email', ' ')
      setActiveStep(0)
    }
  }, [open])

  return (
    <Box className={classes.dialog}>
      {isHome && !currentUser &&
        <Button color="secondary" className={classes.registerBtn} onClick={handleOpen}>
          {t('signup.register')}
        </Button>
      }
      {isSideBar && !currentUser &&
        <Box
          className={classes.registerBtnSideBar}
          onClick={handleOpen}
        >
          <ContactMailIcon className={classes.iconOption} />
          <Link to="/">
            <Typography
              variant="body1"
              className={classes.labelOption}
            >
              {t('signup.register')}
            </Typography>
          </Link>
        </Box>
      }
      <Dialog
        fullScreen={fullScreen}
        maxWidth={maxWidth}
        open={open}
        onClose={handleOpen}
        aria-labelledby="transition-modal-title"
        aria-describedby="transition-modal-description"
        closeAfterTransition
        BackdropComponent={Backdrop}
        BackdropProps={{
          timeout: 500
        }}
      >
        <DialogContent className={classes.dimensions} >
          <Box className={classes.closeIcon}>
            <IconButton
              aria-label="close"
              color="inherit"
              onClick={handleOpen}
            >
              <CloseIcon fontSize="inherit" />
            </IconButton>
          </Box>
          {activeStep !== 0 && (
            <Box className={classes.goBack}>
              <IconButton aria-label="go-back" onClick={handleGoBack}>
                <ArrowBackIcon color="primary" />
              </IconButton>
            </Box>
          )}
          <Box className={classes.register}>
            <Box className={classes.stepperContent}>
              {activeStep === 0 && (
                <>
                  <Typography className={classes.titleRegisterRoleSelector}>{t('signup.register')}</Typography>
                  <Typography className={classes.registerText}>{t('signup.registerText')}</Typography>
                  <SignupRoleSelector onSubmit={handleRoleChange} />
                </>
              )}
              {activeStep === 1 && role === 'donor' && (
                <>
                  <Typography className={classes.titleRegister}>{t('signup.asAdonor')}</Typography>
                  <Typography className={classes.text}>{t('signup.allYouNeed')}</Typography>
                  <Suspense fallback={<CircularProgress />}>
                    <SignupDonor
                      onSubmit={handleCreateAccount}
                      onSubmitWithAuth={handleCreateAccountWithAuth}
                      loading={createAccountLoading || createAccountLoadingAuth}
                      setField={handleSetField}
                      isEmailValid={isEmailValid}
                    >
                      <ValidateEmail
                        isValid={isEmailValid}
                        loading={checkEmailLoading}
                        setField={handleSetField}
                        user={user}
                      />
                    </SignupDonor>
                  </Suspense>
                </>
              )}
              {activeStep === 1 && role === 'sponsor' && (
                <>
                  <Typography className={classes.titleRegister}>{t('signup.asAsponsor')}</Typography>
                  <Typography className={classes.text}>{t('signup.allYouNeed')}</Typography>
                  <Suspense fallback={<CircularProgress />}>
                    <SimpleRegisterForm
                      onSubmit={handleCreateAccount}
                      loading={createAccountLoading}
                      setField={handleSetField}
                      isEmailValid={isEmailValid}
                    >
                      <ValidateEmail
                        isValid={isEmailValid}
                        loading={checkEmailLoading}
                        user={user}
                        setField={handleSetField}
                      />
                    </SimpleRegisterForm>
                  </Suspense>
                </>
              )}
              {activeStep === 1 && role === 'lifebank' && (
                <>
                  <Typography className={classes.titleRegister}>{t('signup.asAbank')}</Typography>
                  <Typography variant="body1" className={classes.text}>{t('signup.preRegistrationRequirement')}</Typography>
                  <Suspense fallback={<CircularProgress />}>
                    <SignupLifeBank
                      onSubmit={handlePreRegisterLifebank}
                      loading={preRegisterLifebankLoading}
                      setField={handleSetField}
                      user={user}
                      isEmailValid={isEmailValid}
                    >
                      <ValidateEmail
                        isValid={isEmailValid}
                        loading={checkEmailLoading}
                        user={user}
                        setField={handleSetField}
                      />
                    </SignupLifeBank>
                  </Suspense>
                </>
              )}
            </Box>
          </Box>
        </DialogContent>
      </Dialog>
      <Snackbar open={openSnackbar.show} autoHideDuration={4000} onClose={handleOpenAlert}>
        <Alert severity={openSnackbar.severity}>
          {openSnackbar.message}
        </Alert>
      </Snackbar>
    </Box>
  )
}
Example #21
Source File: PodRedeemToPoolForm.jsx    From pods-frontend with MIT License 4 votes vote down vote up
export function PodRedeemToPoolForm({ podAddress, userAddress }) {
  const [
    amount,
    setAmount
  ] = useState('')

  const [
    lastRefetchTxId,
    setLastRefetchTxId
  ] = useState(0)

  const weiAmount = ethers.utils.parseEther(amount || '0')

  let podUser = useQuery(podUserQuery, {
    variables: { podAddress, userAddress },
    skip: !userAddress || !podAddress
  })

  let transactions = useQuery(transactionsQuery)

  let loading = podUser.loading || transactions.loading
  let error = podUser.error || transactions.error

  const [redeemToPool, redeemToPoolResult] = useMutation(gql`
    mutation redeemToPoolMutation($podAddress: String!, $amount: Float!) {
      sendTransaction(abi: "Pod", address: $podAddress, fn: "redeemToPool", params: [$amount, "0x0"], gasLimit: 1000000) @client
    }
  `, {
    variables: {
      podAddress,
      amount: weiAmount
    },
    refetchQueries: ['transactionsQuery']
  })

  let redeemToPoolTx
  if (!loading && !error && redeemToPoolResult.data) {
    redeemToPoolTx = transactions.data._transactions.find(tx => tx.id === redeemToPoolResult.data.sendTransaction.id)
  }

  if (redeemToPoolTx && redeemToPoolTx.completed && redeemToPoolTx.id > lastRefetchTxId) {
    setAmount(0)
    podUser.refetch()
    setLastRefetchTxId(redeemToPoolTx.id)
  }

  let sufficientBalance = false

  if (!loading && !error && podUser.data) {
    sufficientBalance = podUser.data.balance.gte(ethers.utils.bigNumberify(weiAmount))
  }

  return (
    <form className="w-full max-w-sm mt-5" onSubmit={(e) => { e.preventDefault(); redeemToPool() } }>
      <div className="md:flex md:items-center mb-3">
        <div className="md:w-1/3">
          <label className="block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4" htmlFor="inline-full-name">
            Redeem to Pool
          </label>
        </div>
        <div className="md:w-2/3">
          <input
            className="bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white focus:border-purple-500"
            id="inline-full-name"
            type="text"
            placeholder="enter Pod token amount"
            value={amount}
            onChange={(e) => { e.preventDefault(); setAmount(e.target.value) } }
            />
        </div>
      </div>
      <div className="md:flex md:items-center">
        <div className="md:w-1/3"></div>
        <div className="md:w-2/3">
          <Button
            disabled={!sufficientBalance}
            onClick={(e) => { e.preventDefault(); redeemToPool(); } }>
            Redeem to Pool
          </Button>
        </div>
      </div>
    </form>
  )
}
Example #22
Source File: GenericOfferFormComponent.js    From lifebank with MIT License 4 votes vote down vote up
GenericOfferFormComponent = ({
  open,
  setOpen,
  sponsor_id,
  isEditing,
  setOffers,
  data,
  offerNotification
}) => {
  const { t } = useTranslation('translations')
  const classes = useStyles()
  const theme = useTheme()
  const fullScreen = useMediaQuery(theme.breakpoints.down('sm'))
  const [disableUrlInput, setDisableUrlInput] = useState(true)
  const imgUrlValueRef = useRef(undefined)
  const [offer, setOffer] = useState()
  const [alignment, setAlignment] = useState('LocalOfferIcon')
  const [updatedOffer, setUpdatedOffer] = useState()
  const [openSnackbar, setOpenSnackbar] = useState({
    show: false,
    message: '',
    severity: 'success'
  })

  const [
    createOffer,
    {
      loading: createOfferLoading,
      data: { insert_offer_one: createOfferResult } = {}
    }
  ] = useMutation(CREATE_OFFER_MUTATION)

  const [
    updateOffer,
    {
      loading: updateOfferLoading,
      data: { update_offer: updateOfferResult } = {}
    }
  ] = useMutation(UPDATE_OFFER_MUTATION)

  const handleSubmit = () => {
    const {
      offer_type,
      online_only,
      description,
      limited,
      quantity,
      start_date,
      end_date,
      offer_name,
      id,
      active,
      cost_in_tokens,
      icon
    } = offer

    const images = JSON.stringify(offer.images)

    if (!isEditing)
      createOffer({
        variables: {
          offer_type,
          online_only: online_only || false,
          description,
          limited,
          quantity: quantity || undefined,
          start_date: start_date || undefined,
          end_date: end_date || undefined,
          cost_in_tokens,
          images,
          sponsor_id,
          active: true,
          offer_name: offer_name,
          icon: icon || 'LocalOfferIcon'
        }
      })
    else {
      updateOffer({
        variables: {
          offer_type,
          online_only,
          description,
          limited,
          quantity: quantity || undefined,
          start_date: start_date || undefined,
          end_date: end_date || undefined,
          cost_in_tokens,
          images,
          offer_name,
          id,
          icon,
          active
        }
      })
      setUpdatedOffer({
        offer_type,
        online_only,
        description,
        limited,
        quantity: quantity || undefined,
        start_date: start_date || undefined,
        end_date: end_date || undefined,
        cost_in_tokens,
        images,
        offer_name,
        id,
        icon,
        active
      })
    }
  }

  const handleAlignment = (event, newAlignment) => {
    setOffer({ ...offer, icon: newAlignment })
    setAlignment(newAlignment)
  }

  useEffect(() => {
    if (data) {
      data.images = JSON.parse(data.images)
      setOffer(data)
    } else
      setOffer({
        limited: true,
        images: [],
        online_only: true
      })
  }, [data])

  useEffect(() => {
    if (updateOfferResult) {
      setOpenSnackbar({
        show: true,
        message: t('offersManagement.offerUpdatedMessage'),
        severity: 'success'
      })
      setOffers((offs) =>
        offs.map((offr) => {
          if (offr.id === updatedOffer.id) offr = updatedOffer
          return offr
        })
      )
    }
  }, [t, updateOfferResult])

  useEffect(() => {
    if (createOfferResult) {
      setOpenSnackbar({
        show: true,
        message: t('offersManagement.offerCreatedMessage'),
        severity: 'success'
      })
      setOffers((offs) => [...offs, createOfferResult])
    }
  }, [t, createOfferResult])

  function executeAddImage(e) {
    if (e.key === 'Enter' && (!disableUrlInput)) {
      e.preventDefault()
      setOffer({
        ...offer,
        images: offer.images.concat(imgUrlValueRef.current.value)
      })
      imgUrlValueRef.current.value = ''
      setDisableUrlInput(true)
    }
  }

  return (
    <Dialog
      fullScreen={fullScreen}
      open={open}
      onClose={() => setOpen(false)}
      TransitionComponent={Transition}
    >
      <Box className={classes.dialog}>
        {fullScreen &&
          < AppBar className={classes.appBar} >
            <Toolbar>
              <IconButton
                className={classes.backIcon}
                onClick={() => setOpen(false)}
                aria-label="close"
              >
                <KeyboardBackspaceIcon />
              </IconButton>
              <Typography variant="h1" className={classes.titleAppBar}>
                {t('offersManagement.addOffer')}
              </Typography>
            </Toolbar>
          </AppBar>
        }
        {!fullScreen &&
          <Box>
            <Box className={classes.closeIcon}>
              <IconButton
                aria-label="close"
                color="inherit"
                size="small"
                onClick={() => setOpen(false)}
              >
                <CloseIcon fontSize="inherit" />
              </IconButton>
            </Box>
            <Typography className={classes.titleModal}>
              {t('offersManagement.addOffer')}
            </Typography>
          </Box>
        }
        {
          offer && (
            <form autoComplete="off" className={classes.form}>
              <TextField
                id="offer-name"
                label={t('offersManagement.offerName')}
                variant="outlined"
                value={offer.offer_name || undefined}
                fullWidth
                onChange={(event) =>
                  setOffer({ ...offer, offer_name: event.target.value })
                }
                className={classes.textField}
              />
              <FormControl variant="outlined" className={classes.textField}>
                <InputLabel id="bussines-type-label">
                  {t('offersManagement.selectOfferType')}
                </InputLabel>
                <Select
                  labelId="offer-type-label"
                  id="offer-type"
                  label={t('offersManagement.selectOfferType')}
                  value={offer.offer_type || ''}
                  onChange={(event) =>
                    setOffer({ ...offer, offer_type: event.target.value })
                  }
                >
                  <MenuItem value="discount">{t('categories.discount')}</MenuItem>
                  <MenuItem value="freeProduct">{t('categories.freeProduct')}</MenuItem>//
                  <MenuItem value="coupon">{t('categories.coupon')}</MenuItem>
                  <MenuItem value="badge">{t('categories.badge')}</MenuItem>//
                  <MenuItem value="benefit">{t('categories.benefit')}</MenuItem>
                </Select>
              </FormControl>
              <TextField
                id="offer-description"
                label={t('offersManagement.offerDescription')}
                variant="outlined"
                value={offer.description || undefined}
                fullWidth
                onChange={(event) =>
                  setOffer({ ...offer, description: event.target.value })
                }
                className={classes.textField}
              />
              <TextField
                id="cost-in-tokens"
                label={t('offersManagement.costInTokens')}
                variant="outlined"
                onKeyDown={(evt) => evt.key === 'e' && evt.preventDefault()}
                value={offer.cost_in_tokens || undefined}
                fullWidth
                InputProps={{
                  inputComponent: NumberFormatCustom,
                }}
                onChange={(event) =>
                  setOffer({ ...offer, cost_in_tokens: event.target.value })
                }
                className={classes.textField}
              />
              <Divider className={classes.divider} />
              <Typography className={classes.boldText} variant="subtitle1">{t('offersManagement.chooseIcon')}</Typography>
              <ToggleButtonGroup
                id="offer-icon"
                value={offer.icon || alignment}
                exclusive
                onChange={handleAlignment}
                aria-label="text alignment"
                className={classes.toggleIcons}
              >
                <ToggleButton value="LocalOfferIcon" className={classes.offerIcon}><LocalOfferIcon /></ToggleButton>
                <ToggleButton value="CardGiftcardIcon" className={classes.offerIcon} ><CardGiftcardIcon /></ToggleButton>
                <ToggleButton value="StarsIcon" className={classes.offerIcon}><StarsIcon /></ToggleButton>
                <ToggleButton value="WhatshotIcon" className={classes.offerIcon}><WhatshotIcon /></ToggleButton>
                <ToggleButton value="AccessTimeIcon" className={classes.offerIcon}><AccessTimeIcon /></ToggleButton>
                <ToggleButton value="StorefrontIcon" className={classes.offerIcon}><StorefrontIcon /></ToggleButton>
                <ToggleButton value="TagFacesIcon" className={classes.offerIcon}><TagFacesIcon /></ToggleButton>
                <ToggleButton value="ShoppingBasketIcon" className={classes.offerIcon}><ShoppingBasketIcon /></ToggleButton>
                <ToggleButton value="RestaurantIcon" className={classes.offerIcon}><RestaurantIcon /></ToggleButton>
                <ToggleButton value="FilterVintageIcon" className={classes.offerIcon}><FilterVintageIcon /></ToggleButton>
                <ToggleButton value="OutdoorGrillIcon" className={classes.offerIcon}><OutdoorGrillIcon /></ToggleButton>
                <ToggleButton value="OfflineBoltIcon" className={classes.offerIcon}><OfflineBoltIcon /></ToggleButton>
              </ToggleButtonGroup>
              <Divider className={classes.divider} />
              <Typography className={classes.boldText} variant="subtitle1">{t('offersManagement.redeemAvailability')}</Typography>
              <FormControl component="fieldset" className={classes.radioGroup}>
                <RadioGroup
                  aria-label="limitation"
                  value={String(offer.limited) || undefined}
                  onChange={(event) => {
                    setOffer({ ...offer, limited: event.target.value })
                  }}
                >
                  <FormControlLabel
                    value="false"
                    control={<Radio />}
                    label={t('offersManagement.unlimited')}
                  />
                  <FormControlLabel
                    value="true"
                    control={<Radio />}
                    label={t('offersManagement.limited')}
                  />
                </RadioGroup>
                {(offer.limited === true || offer.limited === 'true') && (
                  <LimitationHandling
                    setQuantity={(val) => setOffer({ ...offer, quantity: val })}
                    initialDates={[offer.start_date, offer.end_date]}
                    fullWidth
                    setDates={(dates) =>
                      setOffer({
                        ...offer,
                        start_date: dates[0],
                        end_date: dates[1]
                      })
                    }
                    classes={classes}
                  />
                )}
              </FormControl>
              <Divider className={classes.divider} />
              <Typography className={classes.boldText} variant="subtitle1">{t('profile.images')}</Typography>
              <TextField
                id="image-url"
                label={t('offersManagement.imageUrl')}
                variant="outlined"
                fullWidth
                inputRef={imgUrlValueRef}
                onChange={(e) => setDisableUrlInput(e.target.value.length < 1)}
                className={classes.textField}
                onKeyPress={(event) =>
                  executeAddImage(event)
                }
                InputProps={{
                  endAdornment: (
                    <InputAdornment position="end">
                      <IconButton
                        color="secondary"
                        aria-label="add photo url"
                        disabled={disableUrlInput}
                        onClick={() => {
                          setOffer({
                            ...offer,
                            images: offer.images.concat(imgUrlValueRef.current.value)
                          })
                          imgUrlValueRef.current.value = ''
                          setDisableUrlInput(true)
                        }}
                      >
                        <AddIcon />
                      </IconButton>
                    </InputAdornment>
                  )
                }}
              />
              <Box className={classes.addButtonContainer}>
                {offer.images.length < 1 &&
                  <Typography variant="caption">
                    {t('offersManagement.imageRestriction')}
                  </Typography>
                }
              </Box>
              {offer.images.length > 0 && (
                <>
                  {offer.images &&
                    <Box className={classes.carrouselContainer}>
                      <CarouselComponent
                        deleteItem={(url) => {
                          setOffer({
                            ...offer,
                            images: offer.images.filter((p) => p !== url)
                          })
                        }}
                        activeDeletion
                        images={offer.images} />
                    </Box>
                  }
                </>
              )}
              <Box
                style={{ marginTop: '50px' }}
              >
                <Button
                  className={classes.saveBtn}
                  disabled={
                    createOfferLoading ||
                    updateOfferLoading ||
                    !offer.description ||
                    !offer.offer_type ||
                    !offer.cost_in_tokens ||
                    offer.images.length < 1
                  }
                  onClick={() => {
                    handleSubmit()
                    offerNotification()
                    setOpen(false)
                  }}
                  variant="contained"
                  color="primary"
                >
                  {t('offersManagement.addOffer')}
                </Button>
              </Box>
            </form>
          )
        }
      </Box>
    </Dialog >
  )
}
Example #23
Source File: useTokenEntity.js    From feedadoc with MIT License 4 votes vote down vote up
useTokenEntity = (token, entityType) => {
  const entityMutation = getMutationByEntityType(entityType);

  const { error, data } = useQuery(GET_ENTITY_BY_TOKEN, {
    variables: { token },
  });
  const [saveEntity, { error: savingError, data: saveData }] = useMutation(
    entityMutation
  );
  const [entity, setEntity] = useState();
  const [requestState, setRequestState] = useState(
    TOKEN_ENTITY_REQUEST_STATES.LOADING
  );
  const [isSaveSnackbarOpen, setSaveSnackbarOpen] = useState(true);

  if (!entity && data && requestState === TOKEN_ENTITY_REQUEST_STATES.LOADING) {
    const { linkedToken } = data;
    if (linkedToken.__typename != `Full${entityType}`) {
      const error = `Expecting a ${entityType} but received a ${linkedToken.__typename}`;
      console.error(error);
      setRequestState(TOKEN_ENTITY_REQUEST_STATES.LOADING_ERROR);
    } else {
      if (entityType === "Provider") {
        setEntity({
          ...linkedToken,
          requests: linkedToken.requests
            .filter((x) => !x.satisfied)
            .map((x) => x.type),
        });
      } else {
        setEntity(linkedToken);
      }
      setRequestState(TOKEN_ENTITY_REQUEST_STATES.LOADED);
    }
  }

  if (error && requestState === TOKEN_ENTITY_REQUEST_STATES.LOADING) {
    setRequestState(TOKEN_ENTITY_REQUEST_STATES.LOADING_ERROR);
  }

  const setField = (field) => (value) => {
    setEntity((state) => ({
      ...state,
      [field]: value,
    }));
  };

  const save = () => {
    setRequestState(TOKEN_ENTITY_REQUEST_STATES.SAVING);
    saveEntity({ variables: { token, ...entity } })
      .then(({ errors: systemErrors = [], data }) => {
        if (systemErrors.length || data.updateProvider.errors.length) {
          setRequestState(TOKEN_ENTITY_REQUEST_STATES.SAVING_ERROR);
        } else {
          setSaveSnackbarOpen(true);
          setRequestState(TOKEN_ENTITY_REQUEST_STATES.SAVING_SUCCESS);
        }
      })
      .catch((e) => {
        console.error(e);
        setRequestState(TOKEN_ENTITY_REQUEST_STATES.SAVING_ERROR);
      });
  };

  const acknowledgeSaveSnackbar = () => setSaveSnackbarOpen(false);
  if (saveData && saveData.updateProvider.errors.length) {
    return [
      requestState,
      entity,
      saveData.updateProvider.errors.join(". "),
      setField,
      save,
      isSaveSnackbarOpen,
      acknowledgeSaveSnackbar,
    ];
  }
  return [
    requestState,
    entity,
    error || savingError,
    setField,
    save,
    isSaveSnackbarOpen,
    acknowledgeSaveSnackbar,
  ];
}
Example #24
Source File: PodRedeemForm.jsx    From pods-frontend with MIT License 4 votes vote down vote up
export function PodRedeemForm({ podAddress, userAddress }) {
  const [
    amount,
    setAmount
  ] = useState('')

  const [
    lastRefetchTxId,
    setLastRefetchTxId
  ] = useState(0)

  const weiAmount = ethers.utils.parseEther(amount || '0')

  let podUser = useQuery(podUserQuery, {
    variables: { podAddress, userAddress },
    skip: !userAddress || !podAddress
  })

  let transactions = useQuery(transactionsQuery)

  let loading = podUser.loading || transactions.loading
  let error = podUser.error || transactions.error

  const [redeem, redeemResult] = useMutation(gql`
    mutation redeemMutation($podAddress: String!, $amount: Float!) {
      sendTransaction(abi: "Pod", address: $podAddress, fn: "redeem", params: [$amount, "0x0"], gasLimit: 900000) @client
    }
  `, {
    variables: {
      podAddress,
      amount: weiAmount
    },
    refetchQueries: ['transactionsQuery']
  })

  let redeemTx
  if (!loading && !error && redeemResult.data) {
    redeemTx = transactions.data._transactions.find(tx => tx.id === redeemResult.data.sendTransaction.id)
  }

  if (redeemTx && redeemTx.completed && redeemTx.id > lastRefetchTxId) {
    setAmount(0)
    podUser.refetch()
    setLastRefetchTxId(redeemTx.id)
  }

  let sufficientBalance = false

  if (!loading && !error && podUser.data) {
    sufficientBalance = podUser.data.balance.gte(ethers.utils.bigNumberify(weiAmount))
  }

  return (
    <form className="w-full max-w-sm mt-5" onSubmit={(e) => { e.preventDefault(); redeem(); } }>
      <div className="md:flex md:items-center mb-3">
        <div className="md:w-1/3">
          <label className="block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4" htmlFor="inline-full-name">
            Redeem
          </label>
        </div>
        <div className="md:w-2/3">
          <input
            className="bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white focus:border-purple-500"
            id="inline-full-name"
            type="text"
            placeholder="enter Pod token amount"
            value={amount}
            onChange={(e) => { e.preventDefault(); setAmount(e.target.value) } }
            />
        </div>
      </div>
      <div className="md:flex md:items-center">
        <div className="md:w-1/3"></div>
        <div className="md:w-2/3">
          <Button
            disabled={!sufficientBalance}
            onClick={(e) => { e.preventDefault(); redeem(); } }>
            Redeem
          </Button>
        </div>
      </div>
    </form>
  )
}
Example #25
Source File: VolunteerStepper.jsx    From feedadoc with MIT License 4 votes vote down vote up
export default function VolunteerStepper({ steps, location }) {
  const classes = useStyles();
  const [activeStep, setActiveStep] = React.useState(0);
  const [errors, setErrors] = React.useState(null);
  const [variables, setVariables] = React.useState({
    firstName: "",
    lastName: "",
    neighborhood: "",
    city: "",
    state: "",
    country: "",
    latitude: 0.0,
    longitude: 0.0,
    address: "",
    email: "",
    requests: [],
    description: "",
    availabilities: [],
    phone: "",
    social: "",
    over18: false,
  });
  const [mapResult, setMapResult] = useState(null);
  const [isSuccess, setIsSuccess] = useState(false);

  const queryId = queryString.parse(location.search).provider;
  let provider;

  const providerResult = useQuery(GET_PROVIDER, {
    variables: { id: parseInt(queryId) },
  });

  if (providerResult && providerResult.data && providerResult.data.provider) {
    provider = providerResult.data.provider;
  }

  const [createVolunteer, { loading, data, error }] = useMutation(
    CREATE_VOLUNTEER
  );

  const handleNext = () => {
    if (activeStep === steps.length - 1 && variables.over18 === false) {
      setErrors(["You must be over 18 years old to volunteer."]);
    } else if (activeStep === steps.length - 1) {
      createVolunteer({
        variables: { ...variables, providerId: parseInt(queryId) },
      })
        .then(({ errors: systemErrors = [], data }) => {
          const {
            createVolunteer: { volunteer, errors = [] },
          } = data;
          const allErrors = [...(errors || []), ...systemErrors].map((e) =>
            e && e.message ? e.message : e
          );
          if (errors.length) {
            setErrors(errors);
          } else {
            setIsSuccess(true);
          }
        })
        .catch((e) => {
          setErrors([e.message]);
        });
    } else {
      setActiveStep(activeStep + 1);
    }
  };

  const handleBack = () => {
    setActiveStep(activeStep - 1);
  };

  const setField = (name) => (value) => {
    setVariables((vars) => ({ ...vars, [name]: value }));
  };

  const onChange = (e) => setField(e.target.name)(e.target.value);

  const CurrentStep = steps[activeStep] && steps[activeStep].component;

  if (isSuccess) {
    return <Redirect push to="/volunteer/confirmation" />;
  }

  if (!provider) return null;

  return (
    <Paper className={classes.paper}>
      <React.Fragment>
        <Typography
          component="h1"
          variant="h6"
          align="center"
          className={classes.formTitle}
        >
          Offer Help
        </Typography>
        <Typography
          component="h2"
          variant="h5"
          align="center"
          className={classes.heading}
        >
          {`Respond to ${provider.firstName}'s request`}
        </Typography>
        <Typography
          component="h3"
          variant="h6"
          align="center"
          className={classes.details}
        >
          {`The information you provide on this page will be shared with ${provider.firstName}, and they will respond if they still need help. Thank you for volunteering!`}
        </Typography>
        <Stepper activeStep={activeStep} className={classes.stepper}>
          {steps.map(({ label }, index) => (
            <Step key={index} onClick={() => setActiveStep(index)}>
              <StepLabel className={classes.step}>{label}</StepLabel>
            </Step>
          ))}
        </Stepper>
        <React.Fragment>
          <React.Fragment>
            <CurrentStep
              onChange={onChange}
              setField={setField}
              provider={provider}
              setMapResult={setMapResult}
              mapResult={mapResult}
              {...variables}
            />
            <div className={classes.buttons}>
              {activeStep !== 0 && (
                <Button
                  variant="contained"
                  onClick={handleBack}
                  className={classes.backButton}
                >
                  <div className={classes.buttonText}>Back</div>
                </Button>
              )}
              <Button
                variant="contained"
                onClick={handleNext}
                className={classes.forwardButton}
                disabled={loading}
              >
                <div className={classes.buttonText}>
                  {activeStep === steps.length - 1 ? "Volunteer" : "Next"}
                </div>
              </Button>
            </div>
          </React.Fragment>
        </React.Fragment>
      </React.Fragment>
      {errors && (
        <Snackbar open={true} onClose={() => setErrors(null)}>
          <Paper className={classes.error}>
            <ErrorIcon /> {errors.join(" - ")}
          </Paper>
        </Snackbar>
      )}
    </Paper>
  );
}
Example #26
Source File: PodJoinForm.jsx    From pods-frontend with MIT License 4 votes vote down vote up
export default function PodJoinForm({ podAddress, userAddress }) {
  const [
    amount,
    setAmount
  ] = useState('')

  const [
    lastRefetchTxId,
    setLastRefetchTxId
  ] = useState(0)

  const weiAmount = ethers.utils.parseEther(amount || '0')

  let pod = useQuery(podQuery, {
    variables: { podAddress }
  })

  let poolAddress = pod.data ? pod.data.poolAddress : null

  let podUser = useQuery(podUserQuery, {
    variables: { podAddress, userAddress },
    skip: !userAddress || !podAddress
  })

  let pool = useQuery(poolQuery, {
    variables: {
      podAddress,
      poolAddress
    },
    skip: !poolAddress
  })

  let tokenAddress = pool.data ? pool.data.tokenAddress : null

  // console.log({ podAddress, userAddress, poolAddress, tokenAddress })

  let token = useQuery(tokenQuery, {
    variables: {
      podAddress,
      userAddress,
      tokenAddress
    },
    skip: !tokenAddress || !userAddress
  })

  let transactions = useQuery(transactionsQuery)

  let loading = podUser.loading || pool.loading || token.loading || transactions.loading
  let error = podUser.error || pool.error || token.error || transactions.error

  const [approve, approveResult] = useMutation(gql`
    mutation approveMutation($tokenAddress: String!, $podAddress: String!, $amount: Float!) {
      sendTransaction(abi: "ERC20", address: $tokenAddress, fn: "approve", params: [$podAddress, $amount]) @client
    }
  `, {
    variables: {
      tokenAddress,
      podAddress,
      amount: weiAmount
    },
    refetchQueries: ['transactionsQuery']
  })

  let approveTx
  if (!loading && !error && approveResult.data) {
    approveTx = transactions.data._transactions.find(tx => tx.id === approveResult.data.sendTransaction.id)  
  }

  const [deposit, depositResult] = useMutation(gql`
    mutation depositMutation($podAddress: String!, $amount: Float!) {
      sendTransaction(abi: "Pod", address: $podAddress, fn: "deposit", params: [$amount, "0x0"], gasLimit: 1000000) @client
    }
  `, {
    variables: {
      podAddress,
      amount: weiAmount
    },
    refetchQueries: ['transactionsQuery']
  })

  let depositTx
  if (!loading && !error && depositResult.data) {
    depositTx = transactions.data._transactions.find(tx => tx.id === depositResult.data.sendTransaction.id)
  }

  if (approveTx && approveTx.completed && approveTx.id > lastRefetchTxId) {
    token.refetch()
    setLastRefetchTxId(approveTx.id)
  }

  if (depositTx && depositTx.completed && depositTx.id > lastRefetchTxId) {
    setAmount(0)
    token.refetch()
    podUser.refetch()
    pool.refetch()
    setLastRefetchTxId(depositTx.id)
  }

  let needsApproval = true
  // let sufficientBalance = false

  if (!loading && !error && token.data) {
    needsApproval = token.data.allowance.lt(ethers.utils.bigNumberify(weiAmount))
    // sufficientBalance = token.data.balance.gte(ethers.utils.bigNumberify(weiAmount))
  }

  return (
    <form className="w-full max-w-sm mt-5" onSubmit={(e) => { e.preventDefault(); needsApproval ? approve() : deposit() } }>
      <div className="md:flex md:items-center mb-3">
        <div className="md:w-1/3">
          <label className="block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4" htmlFor="inline-full-name">
            Deposit
          </label>
        </div>
        <div className="md:w-2/3">
          <input
            className="bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white focus:border-purple-500"
            id="inline-full-name"
            type="text"
            placeholder="enter Dai amount"
            value={amount}
            onChange={(e) => { e.preventDefault(); setAmount(e.target.value) } }
            />
        </div>
      </div>
      <div className="md:flex md:items-center">
        <div className="md:w-1/3"></div>
        <div className="md:w-2/3">
          <Button
            disabled={!needsApproval}
            onClick={(e) => { e.preventDefault(); approve(); } }>
            Approve
          </Button>
          &nbsp;
          <Button
            disabled={needsApproval}
            onClick={(e) => { e.preventDefault(); deposit(); } }>
            Deposit
          </Button>
        </div>
      </div>
    </form>
  )
}
Example #27
Source File: CartSteps.js    From web with MIT License 4 votes vote down vote up
CartSteps = () => {
  const [country, setCountry] = useState('India');
  const [loading, setLoading] = useState(false);
  const [activeStep, setActiveStep] = useState(1);
  const [userData, setUserData] = useState({});
  const [paymentData, setPaymentData] = useState({});
  const [orderData, setOrderData] = useState({});
  const [discount, setDiscount] = useState(0);
  const cartItems = useStoreState(state => state.cart.items);
  const location = useStoreState(state => state.user.location);
  const emptyCart = useStoreActions(actions => actions.cart.empty);
  const [createOrder, { data: createOrderResult }] = useMutation(
    createOrderMutation,
  );
  const [updateOrder] = useMutation(updateOrderMutation);
  const [verifyCard, { data: verifyCardResult }] = useMutation(
    verifyCardMutation,
  );
  // console.log('data', data, verifyCardResult, createOrderResult);

  useEffect(() => {
    if (location && location.country) {
      setCountry(location.country);
    }
  }, [location]);

  const handleCreateOrder = async gateway => {
    const tokenId = verifyCardResult ? verifyCardResult.verifyCard.id : '';
    const orderId = randomstring.generate(6).toUpperCase();
    const { email, fullName, ...address } = userData;
    const products = cartItems.map(item => {
      return { id: item.id, sku: item.sku };
    });
    const inputData = {
      tokenId,
      orderId,
      customer: { email, fullName, address: { ...address } },
      products,
      discount,
      country: location.country,
      currencyCode: location.currencyCode,
    };

    await createOrder({
      variables: {
        input: inputData,
        gateway,
      },
    });
  };

  const finishOrder = () => {
    // ReactGA.plugin.execute('ecommerce', 'addTransaction', {
    //   id: createOrderResult.createOrder.orderId,
    //   name: 'test checkout', // Product name. Required.
    //   sku: 'DD23444', // SKU/code.
    //   category: 'Party Toys', // Category or variation.
    //   price: '11.99', // Unit price.
    //   quantity: '1', // Quantity.
    // });
    // ReactGA.plugin.execute('ecommerce', 'send');
    // ReactGA.plugin.execute('ecommerce', 'clear');

    setOrderData(createOrderResult.createOrder);
    setActiveStep(4);
    emptyCart();
  };

  useEffect(() => {
    // make verifyCard mutation to generate token
    if (!isEmpty(paymentData)) {
      verifyCard({ variables: { input: paymentData } });
    }
  }, [paymentData]);

  useEffect(() => {
    if (!verifyCardResult) {
      return;
    }
    handleCreateOrder('stripe');
  }, [verifyCardResult]);

  useEffect(() => {
    // console.log('now show success', createOrderResult);
    if (!createOrderResult) {
      return;
    }

    if (country === 'India') {
      // use razor pay
      const options = {
        key: config.razorPayKey, // Enter the Key ID generated from the Dashboard
        amount: `${createOrderResult.createOrder.total}00`,
        currency: 'INR',
        name: config.siteName,
        description: config.description,
        image: config.logo,
        order_id: createOrderResult.createOrder.paymentId, // This is a sample Order ID. Create an Order using Orders API. (https://razorpay.com/docs/payment-gateway/orders/integration/#step-1-create-an-order). Refer the Checkout form table given below
        handler() {
          // do mutation to update payment ID and payment status to success
          updateOrder({
            variables: {
              input: {
                orderId: createOrderResult.createOrder.orderId,
                status: 'paid',
              },
            },
          });
          finishOrder();
        },
        prefill: {
          name: userData.fullName,
          email: userData.email,
          contact: userData.telephone,
        },
        notes: {
          address: userData.address,
        },
        theme: {
          color: theme.mainBrandColor,
        },
      };
      const rzp1 = new Razorpay(options);
      rzp1.open();
      setLoading(false);
    } else {
      finishOrder();
    }
  }, [createOrderResult]);

  useEffect(() => {
    if (!isEmpty(userData) && country === 'India') {
      handleCreateOrder('razorpay');
    }
  }, [userData]);

  return (
    <section className="section">
      <div className="container">
        <Heading>Cart</Heading>
        <Spring
          native
          from={{ opacity: 0 }}
          to={{
            opacity: activeStep !== 1 ? 1 : 0,
            // eslint-disable-next-line prettier/prettier
          }}
        >
          {styles => (
            <animated.div style={styles}>
              <CheckoutProgress activeStep={activeStep} />
            </animated.div>
          )}
        </Spring>
        <div className="columns">
          <Spring
            native
            from={{ marginLeft: '25%' }}
            // eslint-disable-next-line prettier/prettier
            to={{ marginLeft: activeStep === 1 ? '25%' : '0%' }}
          >
            {stylesProps => (
              <animated.div
                style={stylesProps}
                // eslint-disable-next-line prettier/prettier
                className="column section is-half is-hidden-mobile"
              >
                <CartItems
                  cartItems={cartItems}
                  showCheckoutBtn={activeStep === 1}
                  discount={discount}
                  setDiscount={setDiscount}
                  handlePayment={() => {
                    setActiveStep(2);
                  }}
                />
              </animated.div>
            )}
          </Spring>
          <div
            className={`column section ${
              activeStep === 2 ? 'is-hidden-mobile' : ''
            } is-hidden-tablet`}
          >
            <CartItems
              cartItems={cartItems}
              showCheckoutBtn={activeStep === 1}
              discount={discount}
              setDiscount={setDiscount}
              handlePayment={() => {
                setActiveStep(2);
              }}
            />
          </div>
          <div className="column section">
            {activeStep === 2 && (
              <CheckoutForm
                enableReinitialize
                initialValues={{ country: location.country }}
                loading={loading}
                handlePayment={data2 => {
                  setLoading(true);
                  if (country === 'India') {
                    // razorpay payment
                    setUserData(data2);
                  } else {
                    // stripe payment
                    setActiveStep(3);
                    setUserData(data2);
                  }
                }}
              />
            )}
            {activeStep === 3 && (
              <PaymentForm
                handlePayment={data2 => {
                  setPaymentData(data2);
                }}
              />
            )}
            {activeStep === 4 && <PaymentConfirmed orderData={orderData} />}
          </div>
        </div>
      </div>
    </section>
  );
}
Example #28
Source File: signup.jsx    From dineforward with MIT License 4 votes vote down vote up
SignupPage = () => {
  const [termsAccepted, setTermsAccepted] = useState(false);
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [name, setName] = useState('');
  const [errorMessage, setErrorMessage] = useState(null);
  const [alertClosed, setAlertClosed] = useState(false);
  const router = useRouter();

  const [signIn, { loading, client }] = useMutation(gql(CREATE_USER_AND_PASSWORD_AUTH_MUTATION), {
    variables: {
      user: {
        email,
        name,
        password,
        username: email,
        isBusiness: true,
      },
      email,
      password,
    },
    onCompleted: ({ error }) => {
      if (error) throw error;

      // Ensure there's no old unauthenticated data hanging around
      client.resetStore();

      // Don't use the Next.js client-side router here. We must load the
      // next page from the server to trigger the server-side user setup
      // in withIdentity.
      if (typeof window !== 'undefined') window.location.href = nextPage;
      else router.push(nextPage);
    },
    onError: e => {
      let msg = e.message || 'Unknown error';
      if (/duplicate key error/.test(msg)) {
        msg = 'That email address has already been signed up';
      }
      setErrorMessage(msg);
      console.error('User signup error:', e);
    },
  });

  const onSubmit = e => {
    e.preventDefault();
    closeAlert();

    if (!name) {
      setErrorMessage(`Please provide a Name`);
      return;
    }
    if (!email) {
      setErrorMessage(`Please provide an email address`);
      return;
    }
    if (!password) {
      setErrorMessage(`Please provide a password`);
      return;
    }

    if (!loading) signIn();
  };

  const closeAlert = () => {
    setAlertClosed(true);
    setErrorMessage(null);
  };

  const displayError = (!alertClosed && router.query.error) || errorMessage;
  const toggleTerms = () => setTermsAccepted(!termsAccepted);

  React.useEffect(() => {
    window.scrollTo(0, 0);
    document.body.scrollTop = 0;
  });
  const classes = useStyles();

  const errorPage = router.pathname + '?error=${message}'; // Template string interpreted later;
  const authLink = authType =>
    `/auth/${authType}?operation=create&isbusiness=true&onsuccess=${nextPage}&onfailure=${errorPage}`;

  return (
    <div>
      <div
        className={classes.pageHeader}
        style={
          {
            // backgroundImage: 'url(' + image + ')',
            // backgroundSize: 'cover',
            // backgroundPosition: 'top center',
          }
        }
      >
        <div className={classes.container}>
          <Grid container component="main" className={classes.root}>
            <CssBaseline />
            <Grid item xs={false} sm={4} md={7} className={classes.image} />
            <Grid item xs={12} sm={8} md={5} component={Paper} elevation={6} square>
              <div className={classes.paper}>
                {displayError ? (
                  <Alert severity="error" onClose={closeAlert}>
                    {displayError}
                  </Alert>
                ) : null}
                <Avatar className={classes.avatar}>
                  <LockOutlinedIcon />
                </Avatar>
                <Typography component="h1" variant="h5">
                  Sign Up
                </Typography>
                <FormControlLabel
                  classes={{
                    label: classes.label,
                  }}
                  control={
                    <Checkbox
                      tabIndex={-1}
                      onClick={toggleTerms}
                      checkedIcon={<Check className={classes.checkedIcon} />}
                      icon={<CheckBoxOutlineBlankIcon className={classes.uncheckedIcon} />}
                      classes={{
                        checked: classes.checked,
                        root: classes.checkRoot,
                      }}
                      checked={termsAccepted}
                    />
                  }
                  label={
                    <span>
                      I agree to the <a href="/terms">terms and conditions</a>.
                    </span>
                  }
                />
                <div className={classes.textCenter}>
                  <Button color="google" href={authLink('google')} disabled={!termsAccepted}>
                    <i className="fab fa-google-plus-square" /> Sign in with Google
                  </Button>
                  {` `}
                  <Button color="facebook" href={authLink('facebook')} disabled={!termsAccepted}>
                    <i className="fab fa-facebook-square" /> Login with Facebook
                  </Button>
                  {` `}
                  <h4 className={classes.socialTitle}>or with email</h4>
                </div>
                <form className={classes.form} onSubmit={onSubmit}>
                  <TextField
                    className={classes.customFormControlClasses}
                    fullWidth
                    placeholder="Name..."
                    value={name}
                    onChange={e => setName(e.target.value)}
                  />
                  <TextField
                    className={classes.customFormControlClasses}
                    fullWidth
                    autoComplete="email"
                    type="email"
                    placeholder="Email..."
                    value={email}
                    onChange={e => setEmail(e.target.value)}
                  />
                  <TextField
                    className={classes.customFormControlClasses}
                    fullWidth
                    autoComplete="new-password"
                    type="password"
                    placeholder="Password..."
                    value={password}
                    onChange={e => setPassword(e.target.value)}
                  />

                  <div className={classes.textCenter}>
                    <Button
                      type="submit"
                      disabled={loading || !termsAccepted}
                      color="primary"
                    >
                      Get started
                    </Button>
                  </div>
                </form>
              </div>
            </Grid>
          </Grid>
        </div>
      </div>
    </div>
  );
}
Example #29
Source File: MapResults.js    From willow-grandstack with Apache License 2.0 4 votes vote down vote up
export default function MapResults(props) {
  console.log(props.properties)
  const theme = useTheme()

  const [onStarHandler, { data, loading, error }] = useMutation(gql`
    mutation starPropertyMutation($id: ID!) {
      starProperty(id: $id) {
        id
        address
      }
    }
  `)

  const style = {
    padding: '4px',
    color: '#fff',
    cursor: 'pointer',
    background: '#1978c8',
    borderRadius: '50%',
  }

  const useStyles = makeStyles((theme) => ({
    root: {
      display: 'flex',
    },
    paper: {
      padding: theme.spacing(2),
      display: 'flex',
      overflow: 'auto',
      flexDirection: 'column',
    },
    fixedHeight: {
      height: 540,
    },
  }))
  const classes = useStyles(theme)
  const fixedHeightPaper = clsx(classes.paper, classes.fixedHeight)

  const [viewport, setViewport] = useState({
    latitude: 45.667397,
    longitude: -111.054718,
    zoom: 13,
  })

  const [currentProperty, setCurrentProperty] = useState(props.properties[0])

  return (
    <React.Fragment>
      <Grid container spacing={4}>
        <Grid item xs={12} md={2} lg={2}>
          <Paper className={fixedHeightPaper}>
            <StarredProperties />
          </Paper>
        </Grid>
        <Grid item xs={12} md={7} lg={6}>
          <Paper className={fixedHeightPaper}>
            <MapGL
              style={{ width: '100%', height: '100%' }}
              mapStyle="mapbox://styles/mapbox/light-v9"
              accessToken={process.env.REACT_APP_MAPBOX_TOKEN}
              latitude={viewport.latitude}
              longitude={viewport.longitude}
              zoom={viewport.zoom}
              onViewportChange={setViewport}
            >
              {props.properties.map((p, i) => {
                return (
                  <Marker
                    key={i}
                    longitude={p.location.longitude}
                    latitude={p.location.latitude}
                  >
                    <div
                      onClick={() => setCurrentProperty(p)}
                      style={style}
                    ></div>
                  </Marker>
                )
              })}
            </MapGL>
          </Paper>
        </Grid>
        <Grid item xs={12} md={3} lg={4}>
          <Paper className={fixedHeightPaper}>
            <p>{currentProperty.address}</p>
            <Button
              onClick={() =>
                onStarHandler({ variables: { id: currentProperty.id } })
              }
            >
              Star Property
            </Button>
            <ul>
              <li>Square feet: {currentProperty.sqft}</li>
              <li>Bedrooms: {currentProperty.bedrooms}</li>
              <li>Full baths: {currentProperty.full_baths}</li>
              <li>Half baths: {currentProperty.half_baths}</li>
            </ul>
            <GridList cellHeight={160} cols={2}>
              {currentProperty.photos.map((v, i) => (
                <GridListTile key={i} cols={1}>
                  <img src={v.url}></img>
                </GridListTile>
              ))}
            </GridList>
          </Paper>
        </Grid>
      </Grid>
    </React.Fragment>
  )
}