add schedule form validation to ensure at least one occurrence

This commit is contained in:
Keith J. Grant
2022-09-07 10:19:25 -07:00
parent 0005d249c0
commit 078c3ae6d8
3 changed files with 79 additions and 33 deletions

View File

@@ -20,6 +20,7 @@ import ScheduleFormFields from './ScheduleFormFields';
import UnsupportedScheduleForm from './UnsupportedScheduleForm'; import UnsupportedScheduleForm from './UnsupportedScheduleForm';
import parseRuleObj, { UnsupportedRRuleError } from './parseRuleObj'; import parseRuleObj, { UnsupportedRRuleError } from './parseRuleObj';
import buildRuleObj from './buildRuleObj'; import buildRuleObj from './buildRuleObj';
import buildRuleSet from './buildRuleSet';
const NUM_DAYS_PER_FREQUENCY = { const NUM_DAYS_PER_FREQUENCY = {
week: 7, week: 7,
@@ -411,6 +412,26 @@ function ScheduleForm({
} }
}); });
if (values.exceptionFrequency.length > 0) {
let rangeToCheck = 1;
values.frequency.forEach((freq) => {
if (NUM_DAYS_PER_FREQUENCY[freq] > rangeToCheck) {
rangeToCheck = NUM_DAYS_PER_FREQUENCY[freq];
}
});
const ruleSet = buildRuleSet(values, true);
const startDate = DateTime.fromISO(values.startDate);
const endDate = startDate.plus({ days: rangeToCheck });
const instances = ruleSet.between(
startDate.toJSDate(),
endDate.toJSDate(),
true
);
if (instances.length === 0) {
errors.exceptionFrequency = t`This schedule has no occurrences due to the selected exceptions.`;
}
}
return errors; return errors;
}; };

View File

@@ -36,11 +36,19 @@ function pad(num) {
return num < 10 ? `0${num}` : num; return num < 10 ? `0${num}` : num;
} }
export default function buildRuleObj(values) { export default function buildRuleObj(values, includeStart) {
const ruleObj = { const ruleObj = {
interval: values.interval, interval: values.interval,
}; };
if (includeStart) {
ruleObj.dtstart = buildDateTime(
values.startDate,
values.startTime,
values.timezone
);
}
switch (values.frequency) { switch (values.frequency) {
case 'none': case 'none':
ruleObj.count = 1; ruleObj.count = 1;
@@ -91,16 +99,11 @@ export default function buildRuleObj(values) {
ruleObj.count = values.occurrences; ruleObj.count = values.occurrences;
break; break;
case 'onDate': { case 'onDate': {
const [endHour, endMinute] = parseTime(values.endTime); ruleObj.until = buildDateTime(
const localEndDate = DateTime.fromISO(`${values.endDate}T000000`, { values.endDate,
zone: values.timezone, values.endTime,
}); values.timezone
const localEndTime = localEndDate.set({ );
hour: endHour,
minute: endMinute,
second: 0,
});
ruleObj.until = localEndTime.toJSDate();
break; break;
} }
default: default:
@@ -110,3 +113,16 @@ export default function buildRuleObj(values) {
return ruleObj; return ruleObj;
} }
function buildDateTime(dateString, timeString, timezone) {
const localDate = DateTime.fromISO(`${dateString}T000000`, {
zone: timezone,
});
const [hour, minute] = parseTime(timeString);
const localTime = localDate.set({
hour,
minute,
second: 0,
});
return localTime.toJSDate();
}

View File

@@ -4,7 +4,7 @@ import buildRuleObj, { buildDtStartObj } from './buildRuleObj';
window.RRuleSet = RRuleSet; window.RRuleSet = RRuleSet;
const frequencies = ['minute', 'hour', 'day', 'week', 'month', 'year']; const frequencies = ['minute', 'hour', 'day', 'week', 'month', 'year'];
export default function buildRuleSet(values) { export default function buildRuleSet(values, includeStart) {
const set = new RRuleSet(); const set = new RRuleSet();
const startRule = buildDtStartObj({ const startRule = buildDtStartObj({
@@ -15,13 +15,16 @@ export default function buildRuleSet(values) {
set.rrule(startRule); set.rrule(startRule);
if (values.frequency.length === 0) { if (values.frequency.length === 0) {
const rule = buildRuleObj({ const rule = buildRuleObj(
startDate: values.startDate, {
startTime: values.startTime, startDate: values.startDate,
timezone: values.timezone, startTime: values.startTime,
frequency: 'none', timezone: values.timezone,
interval: 1, frequency: 'none',
}); interval: 1,
},
includeStart
);
set.rrule(new RRule(rule)); set.rrule(new RRule(rule));
} }
@@ -29,13 +32,16 @@ export default function buildRuleSet(values) {
if (!values.frequency.includes(frequency)) { if (!values.frequency.includes(frequency)) {
return; return;
} }
const rule = buildRuleObj({ const rule = buildRuleObj(
startDate: values.startDate, {
startTime: values.startTime, startDate: values.startDate,
timezone: values.timezone, startTime: values.startTime,
frequency, timezone: values.timezone,
...values.frequencyOptions[frequency], frequency,
}); ...values.frequencyOptions[frequency],
},
includeStart
);
set.rrule(new RRule(rule)); set.rrule(new RRule(rule));
}); });
@@ -43,13 +49,16 @@ export default function buildRuleSet(values) {
if (!values.exceptionFrequency?.includes(frequency)) { if (!values.exceptionFrequency?.includes(frequency)) {
return; return;
} }
const rule = buildRuleObj({ const rule = buildRuleObj(
startDate: values.startDate, {
startTime: values.startTime, startDate: values.startDate,
timezone: values.timezone, startTime: values.startTime,
frequency, timezone: values.timezone,
...values.exceptionOptions[frequency], frequency,
}); ...values.exceptionOptions[frequency],
},
includeStart
);
set.exrule(new RRule(rule)); set.exrule(new RRule(rule));
}); });