【问题标题】:Adding complete Stripe payment requirement to form将完整的 Stripe 付款要求添加到表单中
【发布时间】:2020-01-03 04:54:39
【问题描述】:

我正在创建一个平台,朋友可以在这里购买朋友星巴克。

用户创建一个请求,其他用户可以通过支付 5 美元来满足这些请求,然后请求用户会收到一张价值 5 美元的星巴克礼品卡。

目前完成请求的唯一要求是消息文本表单(不提交会引发错误),我需要在提交完成请求表单之前添加完成 Stripe 付款的要求。

理想情况下,我希望在 Stripe 付款完成之前禁用履行请求按钮。

填写申请表:

import { connect } from 'react-redux';
import { fulfillRequest, clearErrors } from 'redux/actions/dataActions';

import { Elements } from 'react-stripe-elements';
import CheckoutForm from '../FulfillRequest/Stripe/CheckoutForm';

class FulfillRequest extends Component {
  state = {
    open: false,
    body: '',
    errors: {}
  };

  componentWillReceiveProps(nextProps) {
    if (nextProps.UI.errors) {
      this.setState({
        errors: nextProps.UI.errors
      });
    }
    if (!nextProps.UI.errors && !nextProps.UI.loading) {
      this.setState({ body: '', open: false, errors: {} });
    }
  }

  handleOpen = () => {
    this.setState({ open: true });
  };
  handleClose = () => {
    this.props.clearErrors();
    this.setState({ open: false, errors: {} });
  };
  handleChange = event => {
    this.setState({ [event.target.name]: event.target.value });
  };
  handleSubmit = event => {
    event.preventDefault();
    this.props.fulfillRequest(this.props.requestId, { body: this.state.body });
  };
  render() {
    const {
      classes,
      UI: { loading }
    } = this.props;
    const { errors } = this.state;

    return (
      <Fragment>
        <IconButton onClick={this.handleOpen} color="inherit">
          <TagFaces />
        </IconButton>

        <Dialog
          open={this.state.open}
          onClose={this.handleClose}
          aria-labelledby="form-dialog-title"
          fullWidth
          maxWidth="sm">
          <DialogTitle id="form-dialog-title">Fulfill request</DialogTitle>
          <DialogContent>

            <Elements>
              <CheckoutForm />
            </Elements>

            <Grid
              container
              spacing={0}
              direction="column"
              alignItems="center"
              justify="center">
              {errors.error && (
                <FormHelperText error className={classes.customError}>
                  {errors.error}
                </FormHelperText>
              )}
            </Grid>
            <form onSubmit={this.handleSubmit}>
              <TextField
                autoFocus
                margin="dense"
                multiline
                placeholder="say something"
                id="name"
                name="body"
                label="say something"
                type="text"
                fullWidth
                error={errors.body ? true : false}
                helperText={errors.body}
                onChange={this.handleChange}
              />
              <DialogActions>
                <Button onClick={this.handleClose} color="primary">
                  Cancel
                </Button>
                <Button type="submit" color="primary" disabled={loading}>
                  Fulfill Request
                  {loading && <CircularProgress />}
                </Button>
              </DialogActions>
            </form>
          </DialogContent>
        </Dialog>
      </Fragment>
    );
  }
}

FulfillRequest.propTypes = {
  fulfillRequest: PropTypes.func.isRequired,
  classes: PropTypes.object.isRequired,
  requestId: PropTypes.string.isRequired,
  clearErrors: PropTypes.func.isRequired,
  UI: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  UI: state.UI
});

export default connect(
  mapStateToProps,
  { fulfillRequest, clearErrors }
)(withStyles(styles)(FulfillRequest));

条纹元素:

class CheckoutForm extends Component {
  constructor(props) {
    super(props);
    this.state = { complete: false };
    this.submit = this.submit.bind(this);
  }

  async submit(ev) {
    let { token } = await this.props.stripe.createToken({ name: 'Name' });
    let response = await fetch(
      'https://us-east1-foodmigo-v01-101.cloudfunctions.net/api/charge',
      {
        method: 'POST',
        headers: { 'Content-Type': 'text/plain' },
        body: token.id
      }
    );
    if (response.ok) this.setState({ complete: true });
  }

  render() {
    if (this.state.complete) return <h1>Purchase Complete</h1>;
    return (
      <div className="checkout">
        <p>Would you like to be a hero?</p>
        <CardElement />

        <Button variant="contained" color="secondary" onClick={this.submit}>
          Send
        </Button>
      </div>
    );
  }
}

export default injectStripe(CheckoutForm);

【问题讨论】:

    标签: javascript reactjs stripe-payments


    【解决方案1】:

    不确定您的 Button 组件是如何组成的,但您不能只传递一个 disabled={!this.state.complete} 的 prop 吗?

    编辑:误解了组件的结构。尽管如此,这仍然有效,但是您需要将指示完成的状态从 Form 组件提升到 FulfillRequest 组件中,以便它可以访问它。 FulfillRequest 的状态应该类似于:

    state = {
        open: false,
        body: '',
        errors: {},
        complete: false,
      };
    

    然后您可以创建一个函数,在该父表单中设置值并将其传递给子表单:

      setComplete = (val) => {
        this.setState({
          complete: val
        })
      }
    
    ...
    
    <CheckoutForm setComplete={this.setComplete} complete={this.state.complete}/>
    

    然后在表单解析成功时调用传递的函数设置完成状态:

      async submit(ev) {
        let { token } = await this.props.stripe.createToken({ name: 'Name' });
        let response = await fetch(
          'https://us-east1-foodmigo-v01-101.cloudfunctions.net/api/charge',
          {
            method: 'POST',
            headers: { 'Content-Type': 'text/plain' },
            body: token.id
          }
        );
        if (response.ok) this.props.setComplete(true);
      }
    

    最后,根据结果在父级按钮上设置 disabled 属性(如有必要,还将 this.state.complete 的任何其他实例替换为 CheckoutForm 中的完整属性):

    <Button type="submit" color="primary" disabled={loading || !this.state.complete}>
                      Fulfill Request
                      {loading && <CircularProgress />}
                    </Button>
    

    无法对此进行测试,但它应该可以工作。

    【讨论】:

    • 感谢您的回复! 1.setComplete(val) = () =&gt; { this.setState({ complete: val }) }函数抛出解析错误:预期为“{”。 2.不应该&lt;CheckoutForm setComplete={this.setComplete} complete={this.state.complete}/&gt;吗? 3. 更正 1 为 setComplete = (val) => & 2 throws if (response.ok) setComplete(true);未定义。
    • 不确定解析错误,使用this.setComplete是对的,我有一段时间没有使用类了。第三个也是一样,如果它没有从道具中解构,你必须使用this.props.setComplete。我的错,没有所有组件,我无法建立一个工作示例。让我知道这是否有帮助。
    • 我们去,做到了! setComplete = (val) => 是正确的语法。如果我将项目的前端放在 GitHub 上,您是否足够无私地帮助设计样式? ;) 如您访问 foodmigo.com 所见,样式绝对是可怕的,这是这个难题的最后一个主要部分。非常感谢!
    • 太棒了!更新了答案以修复语法错误。而且我并不完全是一名设计师,但如果您有任何特定的 CSS 问题,我很乐意看看。
    • 听起来不错!谢谢!当问题出现时,我会在这里发表评论。
    猜你喜欢
    • 2015-05-20
    • 2019-06-28
    • 2020-08-16
    • 2020-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    相关资源
    最近更新 更多