Commit 66bcec46 authored by Harumi Jang's avatar Harumi Jang 🤠 Committed by Lauri Timmanee
Browse files

Resolve #3321997 "Entity checkboxes"

parent 635d8027
Loading
Loading
Loading
Loading
+0 −84
Original line number Diff line number Diff line
import { getChildElements } from '../utils';
import * as React from 'react';
import withDefaultValue from './utils/withDefaultValue';
import withAttributes from './utils/withAttributes';
import withStates from './utils/withStates';
import withWrapper from './utils/withWrapper';

const supportedTypes = {
  webform_entity_checkboxes: 'checkbox',
  webform_entity_radios: 'radio',
};

// Component for entity checkboxes and radio buttons.
const EntityCheckboxGroup = ({ element, value = [], setValue, fieldProps }) => {
  if (!(element['#type'] in supportedTypes)) {
    throw new Error(
      `${element['#type']} which was used on ${element['#webform_key']} is not supported by EntityCheckboxGroup.`,
    );
  }
  const type = supportedTypes[element['#type']];

  const onClickHandlerCheckbox = async (e) => {
    if (e.target.checked) {
      setValue(value ? [...value, e.target.value] : [e.target.value]);
    } else {
      if (value.length) {
        const filtered = value.filter((i) => i !== e.target.value);
        setValue(filtered);
      }
    }
  };

  const onClickHandlerRadio = async (e) => {
    setValue(e.target.value);
  };
  const options = getChildElements(element);

  return (
    <>
      {options &&
        options.map((entityId) => {
          const entityName = element[entityId]['#title'];
          return (
            <div key={entityId}>
              <input
                type={type}
                name={`${element['#webform_key']}[${entityId}]`}
                value={entityId}
                onChange={(e) =>
                  type === 'radio'
                    ? onClickHandlerRadio(e)
                    : onClickHandlerCheckbox(e)
                }
                disabled={element['#disabled']}
                hidden={!element['#access']}
                required={element['#required']}
                readOnly={element['#readonly']}
                checked={value.includes(entityId)}
                {...fieldProps}
                id={`${element['#webform_key']}-${entityId}`}
              />
              <label
                htmlFor={`${element['#webform_key']}-${entityId}`}
                className="form-check-label"
              >
                {entityName}
              </label>
            </div>
          );
        })}
    </>
  );
};

export default withStates(
  withDefaultValue(
    withAttributes(
      withWrapper(EntityCheckboxGroup, {
        defaultWrapperType: 'fieldset',
        labelFor: false,
      }),
    ),
  ),
);
+13 −7
Original line number Diff line number Diff line
@@ -12,10 +12,12 @@ const supportedTypes = {
  checkboxes: 'checkbox',
  webform_radios_other: 'radio',
  webform_checkboxes_other: 'checkbox',
  webform_entity_checkboxes: 'checkbox',
  webform_entity_radios: 'radio',
};

// Component for checkboxes and radio buttons.
const WebformCheckboxGroup = ({
// Component for checkboxes or radio buttons that are an options list.
const WebformCheckboxRadioGroup = ({
  element,
  value = [],
  setValue,
@@ -24,7 +26,7 @@ const WebformCheckboxGroup = ({
}: WebformElementProps) => {
  if (!(element['#type'] in supportedTypes)) {
    throw new Error(
      `${element['#type']} which was used on ${element['#webform_key']} is not supported by WebformCheckboxGroup.`,
      `${element['#type']} which was used on ${element['#webform_key']} is not supported by WebformCheckboxRadioGroup.`,
    );
  }

@@ -102,6 +104,7 @@ const WebformCheckboxGroup = ({
  }, [valueOther, valueCheckbox]);

  const childElements = getChildElements(element).map((name) => {
    // Option lists without an 'Other' option.
    if (name !== 'other' && name !== 'radios' && name !== 'checkboxes') {
      return (
        <WebformElement
@@ -113,7 +116,10 @@ const WebformCheckboxGroup = ({
          fieldProps={fieldProps}
          setValue={(target) => {
            const newValue = (target as HTMLInputElement).value;
            if (element['#type'] === 'checkboxes') {
            if (
              element['#type'] === 'checkboxes' ||
              element['#type'] === 'webform_entity_checkboxes'
            ) {
              if ((target as HTMLInputElement).checked) {
                setValueCheckbox([...valueCheckbox, newValue]);
              } else {
@@ -130,8 +136,8 @@ const WebformCheckboxGroup = ({
          error={error}
        />
      );
      // The element has an 'other' option if the child element key is 'checkboxes' or 'radios' so we need to
      // go one level deeper to get the options.
      // The element has an 'Other' option if the child element key is 'checkboxes' or 'radios' so we need to
      // go one level deeper to get the list of options.
    } else if (name == 'checkboxes' || name == 'radios') {
      return getChildElements(element[name]).map((option) => {
        return (
@@ -207,7 +213,7 @@ const WebformCheckboxGroup = ({
};
export default withStates(
  withAttributes(
    withWrapper(WebformCheckboxGroup, {
    withWrapper(WebformCheckboxRadioGroup, {
      defaultWrapperType: 'fieldset',
      labelFor: false,
    }),
+7 −8
Original line number Diff line number Diff line
import EntityCheckboxGroup from './EntityCheckboxGroup';
import WebformAutocomplete from './WebformAutocomplete';
import WebformText from './WebformText';
import WebformSelect from './WebformSelect';
@@ -23,7 +22,7 @@ import WebformDateList from './WebformDateList';
import WebformDate from './WebformDate';
import WebformItem from './WebformItem';
import WebformSubmit from './WebformSubmit';
import WebformCheckboxGroup from './WebformCheckboxGroup';
import WebformCheckboxRadioGroup from './WebformCheckboxRadioGroup';
import WebformButton from './WebformButton';
import WebformTableRow from './WebformTableRow';

@@ -41,17 +40,17 @@ const defaultComponents = {
  // Elements with fixed values.
  autocomplete: WebformAutocomplete,
  checkbox: WebformCheckbox,
  checkboxes: WebformCheckboxGroup,
  checkboxes: WebformCheckboxRadioGroup,
  entity_autocomplete: WebformAutocomplete,
  range: WebformRange,
  radio: WebformCheckbox,
  radios: WebformCheckboxGroup,
  radios: WebformCheckboxRadioGroup,
  select: WebformSelect,
  webform_autocomplete: WebformAutocomplete,
  webform_checkboxes_other: WebformCheckboxGroup,
  webform_entity_checkboxes: EntityCheckboxGroup,
  webform_entity_radios: EntityCheckboxGroup,
  webform_radios_other: WebformCheckboxGroup,
  webform_checkboxes_other: WebformCheckboxRadioGroup,
  webform_entity_checkboxes: WebformCheckboxRadioGroup,
  webform_entity_radios: WebformCheckboxRadioGroup,
  webform_radios_other: WebformCheckboxRadioGroup,
  webform_rating: WebformRating,
  webform_select_other: WebformSelect,
  webform_terms_of_service: WebformTermsOfService,
+21 −0
Original line number Diff line number Diff line
@@ -55,4 +55,25 @@ describe('Checkboxes and radios', () => {
    cy.get(otherInput).should('exist');
    cy.get(otherInput).type('foo');
  });

  it('"entity checkbox group" can be checked and unchecked', () => {
    const managementSelector = 'input[id="edit-entity-checkbox-group-3"]';
    const salesSelector = 'input[id="edit-entity-checkbox-group-5"]';
    cy.get(managementSelector).click().should('be.checked');
    cy.get(salesSelector).click().should('be.checked');
    cy.get(managementSelector).click().should('be.not.checked');
    cy.get(salesSelector).click().should('be.not.checked');
  });

  it('"entity radio group" can be checked and unchecked', () => {
    const bostonSelector = 'input[id="edit-entity-radio-group-10003"]';
    const brightonSelector = 'input[id="edit-entity-radio-group-10027"]';
    const londonSelector = 'input[id="edit-entity-radio-group-10028"]';
    cy.get(bostonSelector).click().should('be.checked');
    cy.get(brightonSelector).should('be.not.checked');
    cy.get(londonSelector).should('be.not.checked');
    cy.get(londonSelector).click().should('be.checked');
    cy.get(bostonSelector).should('be.not.checked');
    cy.get(brightonSelector).should('be.not.checked');
  });
});
+8 −1
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ describe('CSS classes and styles based on Webform configuration', () => {
      .should('have.length', 1)
      .should('have.css', 'margin-top', '16px');
  });
  it('Each checkbox/radio in "Checkboxes custom value with default", "radio group", "checkboxes other", "radios other predefined options" has "test-class-element class', () => {
  it('Each checkbox/radio in "Checkboxes custom value with default", "radio group", "checkboxes other", "radios other predefined options", "entity checkbox group", "radio checkbox group" has "test-class-element class"', () => {
    const selectors = [
      'input[id="edit-checkboxes-custom-value-apple"]',
      'input[id="edit-checkboxes-custom-value-banana"]',
@@ -93,6 +93,13 @@ describe('CSS classes and styles based on Webform configuration', () => {
      'input[id="edit-radios-other-predefined-options-radios-unemployed"]',
      'input[id="edit-radios-other-predefined-options-radios-retired"]',
      'input[id="edit-radios-other-predefined-options-radios-other-"]',
      'input[id="edit-entity-checkbox-group-10"]',
      'input[id="edit-entity-checkbox-group-3"]',
      'input[id="edit-entity-checkbox-group-6"]',
      'input[id="edit-entity-checkbox-group-5"]',
      'input[id="edit-entity-radio-group-10003"]',
      'input[id="edit-entity-radio-group-10027"]',
      'input[id="edit-entity-radio-group-10028"]',
    ];
    selectors.map((sel) => {
      cy.get(sel).should('have.class', 'test-class-element');
Loading