Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[jsx/Form.js] new radio component! #5846

Merged
merged 26 commits into from
Jan 6, 2020

Conversation

maltheism
Copy link
Member

@maltheism maltheism commented Dec 9, 2019

Brief summary of changes

  • I created a "radio" component for the form in LORIS.
  • The component is named: <RadioElement/>
  • Also it will resize well with the browser in the form!

Note: I kept the design simple for now.

Preview:
component_radio_example

Links to related tickets (GitHub, Redmine, ...)

Testing instructions (if applicable)

  1. Checkout PR.
  2. Add to a form.
  3. Test away!

Example replace modules/new_profile/jsx/NewProfileIndex.js with:

import Loader from 'Loader';
import swal from 'sweetalert2';

/**
 * New Profile Form
 *
 * Create a new profile form
 *
 * @author  Shen Wang
 * @version 1.0.0
 * */
class NewProfileIndex extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      configData: {},
      formData: {},
      newData: {},
      isLoaded: false,
      isCreated: false,
      error: false,
      submitDisabled: false,
      radioValue: '',
    };
    this.handleSubmit = this.handleSubmit.bind(this);
    this.setFormData = this.setFormData.bind(this);
    this.fetchData = this.fetchData.bind(this);
    this.handleRadio = this.handleRadio.bind(this);
  }

  handleRadio(formElement, value) {
    const state = Object.assign({}, this.state);
    state.formData.radioGender = value;
    console.log(value);
    this.setState(state);
  }

  componentDidMount() {
    this.fetchData()
      .then(() => this.setState({isLoaded: true}));
  }

  /**
   * Retrieve data from the provided URL and save it in state
   *
   * @return {object}
   */
  fetchData() {
    return fetch(this.props.dataURL,
      {credentials: 'same-origin'})
      .then((resp) => resp.json())
      .then((data) => this.setState({configData: data.fieldOptions}))
      .catch((error) => {
        this.setState({error: true});
      });
  }
  /**
   * It checks the date of birth and Expected Date of Confinement,
   * the date fields must match.
   * If match, this function will return true.
   *
   * @return {boolean}
   */
  validateMatchDate() {
    let validate = false;
    const formData = this.state.formData;
    if (formData.dobDate !== formData.dobDateConfirm) {
      swal.fire('Error!', 'Date of Birth fields must match', 'error');
    } else if (this.state.configData['edc'] === 'true' &&
      (formData.edcDate !== formData.edcDateConfirm)
    ) {
      swal.fire('Error!', 'EDC fields must match', 'error');
    } else {
      validate = true;
    }
    return validate;
  }

  /**
   * Handles form submission
   *
   * @param {event} e - Form submission event
   */
  handleSubmit(e) {
    e.preventDefault();
    const match = this.validateMatchDate();
    if (!match) {
      this.setState({
        isCreated: false,
      });
    } else {
      let formData = this.state.formData;
      let formObject = new FormData();
      for (let key in formData) {
        if (formData[key] !== '') {
          formObject.append(key, formData[key]);
        }
      }
      formObject.append('fire_away', 'New Candidate');

      // disable button to prevent form resubmission.
      this.setState({submitDisabled: true});

      fetch(this.props.submitURL, {
        method: 'POST',
        cache: 'no-cache',
        credentials: 'same-origin',
        body: formObject,
      })
        .then((resp) => {
          if (resp.ok && resp.status === 201) {
            resp.json().then((data) => {
              this.setState({newData: data});
              this.setState({isCreated: true});
            });
          } else {
            resp.json().then((message) => {
              // enable button for form resubmission.
              this.setState({submitDisabled: false});
              swal.fire('Error!', message, 'error');
            });
          }
        })
        .catch((error) => {
          console.error(error);
        });
    }
  }

  /**
   * Set the form data based on state values of child elements/components
   *
   * @param {string} formElement - name of the selected element
   * @param {string} value - selected value for corresponding form element
   */
  setFormData(formElement, value) {
    let formData = Object.assign({}, this.state.formData);
    formData[formElement] = value;

    this.setState({formData: formData});
  }

  render() {
    // If error occurs, return a message.
    if (this.state.error) {
      return <h3>An error occured while loading the page.</h3>;
    }

    // Waiting for async data to load
    if (!this.state.isLoaded) {
      return <Loader/>;
    }
    let profile = null;
    let edc = null;
    let pscid = null;
    let site = null;
    let minYear = this.state.configData.minYear;
    let maxYear = this.state.configData.maxYear;
    let dateFormat = this.state.configData.dobFormat;

    if (this.state.configData['edc'] === 'true') {
      edc =
        <div>
          <DateElement
            name = "edcDate"
            label = "Expected Date of Confinement"
            minYear = {minYear}
            maxYear = {maxYear}
            dateFormat = {dateFormat}
            onUserInput = {this.setFormData}
            value = {this.state.formData.edcDate}
            required = {true}
          />
          <DateElement
            name = "edcDateConfirm"
            label = "Confirm EDC"
            minYear = {minYear}
            maxYear = {maxYear}
            dateFormat = {dateFormat}
            onUserInput = {this.setFormData}
            value = {this.state.formData.edcDateConfirm}
            required = {true}
          />
        </div>;
    }
    if (this.state.configData['pscidSet'] === 'true') {
      pscid =
        <TextboxElement
          name = "pscid"
          label = "PSCID"
          onUserInput = {this.setFormData}
          value = {this.state.formData.pscid}
          required = {true}
        />;
    }
    if (this.state.configData['site'] !== null) {
      site =
        <SelectElement
          name = "site"
          label = "Site"
          options = {this.state.configData.site}
          onUserInput = {this.setFormData}
          value = {this.state.formData.site}
          required = {true}
        />;
    }
    if (!this.state.isCreated) {
      profile = (
        <FormElement
          name = "newProfileForm"
          onSubmit = {this.handleSubmit}
        >
          <DateElement
            name = "dobDate"
            label = "Date of Birth"
            minYear = {minYear}
            maxYear = {maxYear}
            dateFormat = {dateFormat}
            onUserInput = {this.setFormData}
            value = {this.state.formData.dobDate}
            required = {true}
          />
          <DateElement
            name = "dobDateConfirm"
            label = "Date of Birth Confirm"
            minYear = {minYear}
            maxYear = {maxYear}
            dateFormat = {dateFormat}
            onUserInput = {this.setFormData}
            value = {this.state.formData.dobDateConfirm}
            required = {true}
          />
          {edc}
          <SelectElement
            name = "sex"
            label = "Sex"
            options = {this.state.configData.sex}
            onUserInput = {this.setFormData}
            value = {this.state.formData.sex}
            required = {true}
          />
          {site}
          {pscid}
          <SelectElement
            name = "project"
            label = "Project"
            options = {this.state.configData.project}
            onUserInput = {this.setFormData}
            value = {this.state.formData.project}
            required = {true}
          />
          <ButtonElement
            name = "fire_away"
            label = "Create"
            id = "button"
            type = "submit"
            disabled={this.state.submitDisabled}
          />
          <RadioElement
            name={'myRadio'}
            label={'Radio example'}
            options={{
              Male: 'male',
              Female: 'female',
            }}
            checked={this.state.formData.radioGender}
            required={true}
            onUserInput={this.handleRadio}
          />
        </FormElement>
      );
    } else {
      profile = (
        <div>
          <p>New candidate created. DCCID: {this.state.newData.candID} PSCID: {this.state.newData.pscid} </p>
          <p><a href = {'/' + this.state.newData.candID}> Access this candidate </a></p>
          <p><a href = "/new_profile/" > Recruit another candidate </a></p>
        </div>
      );
    }
    return (
      <FieldsetElement legend={'Create a New Profile'}>
        {profile}
      </FieldsetElement>
    );
  }
}
window.addEventListener('load', () => {
  ReactDOM.render(
    <NewProfileIndex
      dataURL = {`${loris.BaseURL}/new_profile/?format=json`}
      submitURL = {`${loris.BaseURL}/new_profile/`}
      hasPermission = {loris.userHasPermission}
    />,
    document.getElementById('lorisworkspace')
  );
});

@maltheism maltheism added Category: Feature PR or issue that aims to introduce a new feature Area: UI PR or issue related to the user interface Passed manual tests PR has been successfully tested by at least one peer labels Dec 9, 2019
@maltheism maltheism requested a review from zaliqarosli December 9, 2019 16:53
Copy link
Contributor

@zaliqarosli zaliqarosli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

last few things to fix up, then i think we're good!

jsx/Form.js Outdated Show resolved Hide resolved
jsx/Form.js Outdated Show resolved Hide resolved
jsx/Form.js Show resolved Hide resolved
jsx/Form.js Outdated Show resolved Hide resolved
maltheism and others added 3 commits December 9, 2019 12:51
Co-Authored-By: Zaliqa <zaliqa.rosli@mcin.ca>
Co-Authored-By: Zaliqa <zaliqa.rosli@mcin.ca>
@maltheism maltheism requested a review from zaliqarosli December 9, 2019 18:02
@maltheism
Copy link
Member Author

@zaliqarosli thanks. I made changes from your suggestions. Ready for re-review.

jsx/Form.js Outdated Show resolved Hide resolved
jsx/Form.js Outdated Show resolved Hide resolved
jsx/Form.js Outdated Show resolved Hide resolved
Misotheism and others added 4 commits December 9, 2019 13:41
Co-Authored-By: Zaliqa <zaliqa.rosli@mcin.ca>
Co-Authored-By: Zaliqa <zaliqa.rosli@mcin.ca>
Co-Authored-By: Zaliqa <zaliqa.rosli@mcin.ca>
@maltheism
Copy link
Member Author

@zaliqarosli thanks added the changes and you're right the props.value is unnecessary.

Copy link
Contributor

@zaliqarosli zaliqarosli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will test in a second!

@zaliqarosli
Copy link
Contributor

hey @maltheism i'm trying to test this and it looks to me that the new_profile implementation in the PR description is out of date.

It looks to me that a selected radio button needs a "checked" attribute. I don't see this implemented in the component anywhere so i'm not sure how to define the handleRadio function. is there another way of setting the chosen radio button value? could you test this on your end and see what we're missing?

jsx/Form.js Show resolved Hide resolved
@christinerogers christinerogers added the Release: Add to release notes PR whose changes should be highlighted in the release notes label Dec 10, 2019
@maltheism
Copy link
Member Author

Hi @zaliqarosli I didn't think of adding a this.props.checked. I can see that as being useful for showing a module with a default radio input already selected. See my latest commit and I also updated the example code above for the new_profile to show how it works.

@maltheism
Copy link
Member Author

@zaliqarosli see latest commit. I made the RadioElement have a state value that's associated with what ends up being checked. This helps the inputs for the RadioElement refresh when one is clicked because the input checked becomes true with the others being false.

jsx/Form.js Outdated Show resolved Hide resolved
jsx/Form.js Outdated Show resolved Hide resolved
jsx/Form.js Outdated Show resolved Hide resolved
@maltheism
Copy link
Member Author

@zaliqarosli I added the latest suggestions.

Copy link
Contributor

@zaliqarosli zaliqarosli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

last changes! tested with these changes and it works beautifully. thanks @maltheism !

jsx/Form.js Outdated Show resolved Hide resolved
jsx/Form.js Outdated Show resolved Hide resolved
jsx/Form.js Outdated Show resolved Hide resolved
maltheism and others added 3 commits December 16, 2019 18:13
Co-Authored-By: Zaliqa <zaliqa.rosli@mcin.ca>
Co-Authored-By: Zaliqa <zaliqa.rosli@mcin.ca>
Co-Authored-By: Zaliqa <zaliqa.rosli@mcin.ca>
Copy link
Contributor

@zaliqarosli zaliqarosli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉🎉 🎉 🎉

@zaliqarosli zaliqarosli added the Passed manual tests PR has been successfully tested by at least one peer label Dec 16, 2019
jsx/Form.js Outdated Show resolved Hide resolved
Co-Authored-By: Zaliqa <zaliqa.rosli@mcin.ca>
Copy link
Contributor

@PapillonMcGill PapillonMcGill left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice addition for field where values are enum type.

@driusan driusan merged commit 175743c into aces:master Jan 6, 2020
lingma pushed a commit to lingma/Loris that referenced this pull request Jan 6, 2020
Create radio button component.
@ridz1208 ridz1208 added this to the 23.0.0 milestone Jan 7, 2020
@maltheism maltheism deleted the master_new_component_radio branch May 24, 2020 02:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: UI PR or issue related to the user interface Category: Feature PR or issue that aims to introduce a new feature Passed manual tests PR has been successfully tested by at least one peer Release: Add to release notes PR whose changes should be highlighted in the release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants