webpack/JobWizard/steps/Schedule/ScheduleRecurring.js
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,
};