theforeman/foreman_remote_execution

View on GitHub
webpack/JobWizard/steps/Schedule/ScheduleRecurring.js

Summary

Maintainability
B
4 hrs
Test Coverage
import React, { useEffect, useState, useCallback } from 'react';
import PropTypes from 'prop-types';
import {
  Form,
  FormGroup,
  Radio,
  TextInput,
  ValidatedOptions,
  Divider,
} from '@patternfly/react-core';
import { ExclamationCircleIcon } from '@patternfly/react-icons';
import { translate as __ } from 'foremanReact/common/I18n';
import { RepeatOn } from './RepeatOn';
import { SCHEDULE_TYPES } from '../../JobWizardConstants';
import { PurposeField } from './PurposeField';
import { DateTimePicker } from '../form/DateTimePicker';
import { WizardTitle } from '../form/WizardTitle';

export const ScheduleRecurring = ({
  scheduleValue,
  setScheduleValue,
  setValid,
}) => {
  const {
    repeatType,
    repeatAmount,
    repeatData,
    startsAt,
    startsBefore,
    ends,
    isNeverEnds,
    isFuture,
    purpose,
  } = scheduleValue;
  const [validEnd, setValidEnd] = useState(true);
  const [repeatValidated, setRepeatValidated] = useState('default');
  const handleRepeatInputChange = newValue => {
    if (!newValue.length) newValue = 0;
    setRepeatValidated(
      !newValue || parseInt(newValue, 10) >= 1 ? 'default' : 'error'
    );
    setScheduleValue(current => ({
      ...current,
      repeatAmount: newValue,
    }));
  };
  const [repeatValid, setRepeatValid] = useState(true);

  const wrappedSetValid = useCallback(setValid, []);
  useEffect(() => {
    if (isNeverEnds) setValidEnd(true);
    else if (!ends) setValidEnd(true);
    else if (
      !startsAt.length &&
      new Date().getTime() <= new Date(ends).getTime()
    )
      setValidEnd(true);
    else if (new Date(startsAt).getTime() <= new Date(ends).getTime())
      setValidEnd(true);
    else {
      setValidEnd(false);
    }

    if (!validEnd || !repeatValid) {
      wrappedSetValid(false);
    } else if (isFuture && startsAt.length) {
      wrappedSetValid(true);
    } else if (!isFuture) {
      wrappedSetValid(true);
    } else {
      wrappedSetValid(false);
    }
  }, [
    wrappedSetValid,
    isNeverEnds,
    startsAt,
    startsBefore,
    isFuture,
    validEnd,
    repeatValid,
    ends,
  ]);

  return (
    <>
      <WizardTitle title={SCHEDULE_TYPES.RECURRING} />
      <Form className="schedule-tab">
        <FormGroup label={__('Starts')} fieldId="schedule-starts">
          <div className="pf-c-form">
            <FormGroup fieldId="schedule-starts-now">
              <Radio
                ouiaId="schedule-start-now"
                isChecked={!isFuture}
                onChange={() =>
                  setScheduleValue(current => ({
                    ...current,
                    startsAt: '',
                    startsBefore: '',
                    isFuture: false,
                  }))
                }
                name="start-now"
                id="start-now"
                label={__('Now')}
              />
            </FormGroup>
            <FormGroup fieldId="start-at-date">
              <Radio
                ouiaId="schedule-start-at-date"
                isChecked={isFuture}
                onChange={() =>
                  setScheduleValue(current => ({
                    ...current,
                    startsAt: new Date().toISOString(),
                    isFuture: true,
                  }))
                }
                name="start-at"
                id="start-at"
                className="schedule-radio"
                label={
                  <div className="schedule-radio-wrapper">
                    <div className="schedule-radio-title">{__('At')}</div>
                    <DateTimePicker
                      ariaLabel="starts at"
                      dateTime={startsAt}
                      setDateTime={newValue =>
                        setScheduleValue(current => ({
                          ...current,
                          startsAt: newValue,
                        }))
                      }
                      isDisabled={!isFuture}
                    />
                  </div>
                }
              />
            </FormGroup>
          </div>
        </FormGroup>

        <Divider component="div" />
        <RepeatOn
          repeatType={repeatType}
          repeatData={repeatData}
          setRepeatType={newValue => {
            setScheduleValue(current => ({
              ...current,
              repeatType: newValue,
              startsBefore: '',
            }));
          }}
          setRepeatData={newValue => {
            setScheduleValue(current => ({
              ...current,
              repeatData: newValue,
            }));
          }}
          setValid={setRepeatValid}
        />
        <Divider component="div" />
        <FormGroup label={__('Ends')} fieldId="schedule-ends">
          <div className="pf-c-form">
            <FormGroup fieldId="schedule-ends-never">
              <Radio
                ouiaId="schedule-never-ends"
                isChecked={isNeverEnds}
                onChange={() =>
                  setScheduleValue(current => ({
                    ...current,
                    isNeverEnds: true,
                    ends: null,
                    repeatAmount: null,
                  }))
                }
                name="never-ends"
                id="never-ends"
                label={__('Never')}
              />
            </FormGroup>
            <FormGroup
              fieldId="ends-on-date"
              validated={
                validEnd ? ValidatedOptions.noval : ValidatedOptions.error
              }
              helperTextInvalid={__('End time needs to be after start time')}
              helperTextInvalidIcon={<ExclamationCircleIcon />}
            >
              <Radio
                ouiaId="schedule-ends-on-date"
                isChecked={!!ends}
                onChange={() =>
                  setScheduleValue(current => ({
                    ...current,
                    ends: new Date().toISOString(),
                    isNeverEnds: false,
                    repeatAmount: null,
                  }))
                }
                name="ends-on"
                id="ends-on"
                className="schedule-radio"
                label={
                  <div className="schedule-radio-wrapper">
                    <div className="schedule-radio-title">{__('On')}</div>
                    <DateTimePicker
                      ariaLabel="ends on"
                      dateTime={ends}
                      isDisabled={!ends}
                      setDateTime={newValue => {
                        setScheduleValue(current => ({
                          ...current,
                          ends: newValue,
                        }));
                      }}
                    />
                  </div>
                }
              />
            </FormGroup>
            <FormGroup fieldId="ends-after">
              <Radio
                ouiaId="schedule-ends-after"
                isChecked={repeatAmount === 0 || !!repeatAmount}
                onChange={() =>
                  setScheduleValue(current => ({
                    ...current,
                    ends: null,
                    isNeverEnds: false,
                    repeatAmount: 1,
                  }))
                }
                name="ends-after"
                id="ends-after"
                className="schedule-radio"
                label={
                  <div className="schedule-radio-wrapper">
                    <div className="schedule-radio-title">{__('After')}</div>
                    <FormGroup
                      helperTextInvalid={__(
                        'Repeat amount can only be a positive number'
                      )}
                      validated={repeatValidated}
                      className="schedule-radio-repeat-text"
                    >
                      <TextInput
                        ouiaId="repeat-amount"
                        id="repeat-amount"
                        value={repeatAmount || ''}
                        type="number"
                        onChange={handleRepeatInputChange}
                        isDisabled={!(repeatAmount === 0 || !!repeatAmount)}
                      />
                    </FormGroup>
                    <div className="schedule-radio-occurences">
                      {__('occurences')}
                    </div>
                  </div>
                }
              />
            </FormGroup>
          </div>
        </FormGroup>
        <Divider component="div" />
        <PurposeField
          purpose={purpose}
          setPurpose={newValue => {
            setScheduleValue(current => ({
              ...current,
              purpose: newValue,
            }));
          }}
        />
      </Form>
    </>
  );
};

ScheduleRecurring.propTypes = {
  scheduleValue: PropTypes.shape({
    repeatType: PropTypes.string.isRequired,
    repeatAmount: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    repeatData: PropTypes.object,
    startsAt: PropTypes.string,
    startsBefore: PropTypes.string,
    ends: PropTypes.string,
    isFuture: PropTypes.bool,
    isNeverEnds: PropTypes.bool,
    purpose: PropTypes.string,
  }).isRequired,
  setScheduleValue: PropTypes.func.isRequired,
  setValid: PropTypes.func.isRequired,
};