Search code examples
javascriptreactjsreact-routerconditional-statementsconditional-rendering

on submit button click, execute function then submit form react.js


I have an order form that currently takes a users input and posts it into a dynamo db table on submit.

Right now, that's all the "submit" button does.

I want the on click to instead calculate a price based off of the users input, hide the form, display the price with an "accept and schedule" button, that then posts to dynamo db.

      -----------------I am very new to to react js so I apologize if my code is sloppy. -------------------

I figured that my function to handle the calculation would look something like the following, as the price is based off of the property square footage in increments of 500.

let base_price = 149.99; 
if(sqft > 2000){
  let overage = sqft - 2000;
  let percentage = Math.ceil(overage % 500) * 10;
  base_price += base_price * percentage;
}

Now here is my current order form code:

import React, { Component } from "react";
import { InputGroup, Row, Form, Col, FormGroup, FormControl, ControlLabel } from "react-bootstrap";
import LoaderButton from "../components/LoaderButton";
import config from "../config";
import { API } from "aws-amplify";


export default class OrderForm extends Component {
  constructor(props) {
    super(props);

    this.state = {
      isLoading: null,
      streetAddress: "",
      streetAddress2: "",
      city: "",
      state: "",
      zipCode: "",
      propertySqft: "",
      packageSelected: this.props.location.state,
    };
  }

  validateForm() {
    return this.state.streetAddress.length > 0;
    return this.state.streetAddress2.legnth >= 0;
    return this.state.city.length > 0;
    return this.state.state.length > 0;
    return this.state.zipCode.length > 0;
    return this.state.propertySqft.length > 0;
    return this.state.packageSelected.length > 0;
}

  handleChange = event => {
    this.setState({
      [event.target.id]: event.target.value,

    });


  }

  handleSubmit = async event => {
    event.preventDefault();

  this.setState({ isLoading: true });
  try {
    await this.createJob({
      streetAddress: this.state.streetAddress,
      streetAddress2: this.state.streetAddress2,
      city: this.state.city,
      state: this.state.state,
      zipCode: this.state.zipCode,
      propertySqft: this.state.propertySqft,
      packageSelected: this.state.packageSelected,
    });
    this.props.history.push("/Scheduled");
  } catch (e) {
    alert(e);
    this.setState({ isLoading: false });
  }
}

createJob(job) {
  return API.post("dynamodbname", "/prapp", {
    body: job
  });
}

  render() {
    var centerText = {textAlign: "center"}
    return (
      <div className="NewJob">
        <Form onSubmit={this.handleSubmit}>

    <Form.Group controlId="packageSelected">
      <Form.Label>
      </Form.Label>
        <InputGroup>
            <InputGroup.Prepend>
            <InputGroup.Text id="inputGroupPrepend">Package Selected:</InputGroup.Text>
            </InputGroup.Prepend>{" "}

      <Form.Control style={centerText} onChange={this.handleChange} plaintext readOnly defaultValue={this.props.location.state} />
        </InputGroup>
  </Form.Group>




  <Form.Group controlId="streetAddress">
    <Form.Label>Address 1</Form.Label>
    <Form.Control onChange={this.handleChange} value={this.state.streetAddress} placeholder="Property Address" />
  </Form.Group>

  <Form.Group controlId="streetAddress2">
    <Form.Label>Address 2</Form.Label>
    <Form.Control onChange={this.handleChange} value={this.state.streetAddress2} placeholder="Apartment, studio, or floor" />
  </Form.Group>

  <Form.Row>
    <Form.Group as={Col} controlId="city">
      <Form.Label>City</Form.Label>
      <Form.Control onChange={this.handleChange} value={this.state.city} placeholder="City" />
    </Form.Group>

    <Form.Group as={Col} controlId="state">
      <Form.Label>State</Form.Label>
      <Form.Control onChange={this.handleChange} value={this.state.state} as="select">
    <option value="AL">State</option>
    <option value="AL">Alabama</option>
    <option value="AK">Alaska</option>
    <option value="AZ">Arizona</option>
    <option value="AR">Arkansas</option>
    <option value="CA">California</option>
    <option value="CO">Colorado</option>
    <option value="CT">Connecticut</option>
    <option value="DE">Delaware</option>
      </Form.Control>
    </Form.Group>

    <Form.Group as={Col} controlId="zipCode">
      <Form.Label>Zip</Form.Label>
      <Form.Control onChange={this.handleChange} value={this.state.zipCode} placeholder="Zip Code" />
    </Form.Group>
    </Form.Row>
        <Form.Group controlId="propertySqft">
      <Form.Label>Square Feet</Form.Label>
      <Form.Control onChange={this.handleChange} value={this.state.propertySqft} placeholder="1234" />
    </Form.Group>


  <Form.Group id="formGridCheckbox">
    <Form.Check type="checkbox" label="I agree to terms and services" />
  </Form.Group>

  <LoaderButton
            block
            bsStyle="primary"
            bsSize="large"
            disabled={!this.validateForm()}
            type="submit"
            isLoading={this.state.isLoading}
            text="Calculate Price"
            loadingText="Calculating your price…."
          />
</Form>
      </div>
    );
  }
}

So how would I go about instead the on submit triggers a function that calculates a price based off of the users input, hide the form, display the price with an "accept and schedule" button, and then posts to dynamo db?

If anyone could share either some resources or insight on how I should go about executing this, that would be extremely appreciated!

Images of calculation debugger:

property sqft is 5000

Overage is 3000

Percentage is Zero?

when set to 5001 sqft, percentage is only 10?


Solution

  • In state, have a value called totalPrice, initialized at null, and add a function that get's met before the official onSubmit. It could look something like this.

    checkPrice = () =>{
        //YOUR PRICE EVAL BASED ON USER INPUT
        this.setState({totalPrice: YOUR_PRICE_EVAL})
    }
    

    In your render, have a condition that says if totalPrice then show price and two buttons (continue, which will execute form submission, or back, which will perform setState({totalPrice: null}) And reveal the form again.

     {this.state.totalPrice ? (
          <div>
            Your price is {this.state.totalPrice}
            <button onClick={this.handleSubmit}>Continue?</button>
            <button onClick={()=>{this.setState({totalPrice: null})}}>Back to Eval</button>
          </div>
        ) : (
          <Form onSubmit={this.checkPrice}>
             ...
          </Form>
    

    Here is a quick code sandbox. The code probably doesn't match up 100% with yours but it should be enough to point you in the right direction.

    Alternatively you can check out Ant Design's Popconfirm component. Basically you wrap it around whatever is going to be clicked (i.e. the submit button) And before it submit's anything the component will render a popup. You can populate the popup with "Your price is..." and calculate the final price. Then pass the props onConfirm={YOUR_SUBMIT_FUNCTION} onCancel={()=>{this.setState({totalPrice: null})}}