Allow schedules to skip weekends (#1505)

* allow schedules to skip weekends

* wording

* release note

* skip weekend in upcoming dates as well

* Clean UI

* Move switch to the date selection modal
This commit is contained in:
Pol Eyschen
2023-08-19 21:55:47 +02:00
committed by GitHub
parent 79f4d02350
commit 639720b6fd
5 changed files with 113 additions and 4 deletions

View File

@@ -203,6 +203,8 @@ export default function ScheduleDetails({ modalProps, actions, id }) {
start: monthUtils.currentDay(),
frequency: 'monthly',
patterns: [],
skipWeekend: false,
weekendSolveMode: 'after',
};
let schedule = {
posts_transaction: false,
@@ -411,7 +413,6 @@ export default function ScheduleDetails({ modalProps, actions, id }) {
// This is derived from the date
let repeats = state.fields.date ? !!state.fields.date.frequency : false;
return (
<Modal
title={payee ? `Schedule: ${payee.name}` : 'Schedule'}
@@ -527,7 +528,7 @@ export default function ScheduleDetails({ modalProps, actions, id }) {
</View>
<Stack direction="row" align="flex-start">
<View style={{ flex: 1 }}>
<View style={{ flex: 1, width: '13.44rem' }}>
{repeats ? (
<RecurringSchedulePicker
value={state.fields.date}

View File

@@ -14,6 +14,7 @@ import Select from '../common/Select';
import Stack from '../common/Stack';
import Text from '../common/Text';
import View from '../common/View';
import { Checkbox } from '../forms';
import { useTooltip, Tooltip } from '../tooltips';
import DateSelect from './DateSelect';
@@ -54,6 +55,8 @@ function parseConfig(config) {
interval: 1,
frequency: 'monthly',
patterns: [createMonthlyRecurrence(monthUtils.currentDay())],
skipWeekend: false,
weekendSolveMode: 'before',
}
);
}
@@ -131,6 +134,22 @@ function reducer(state, action) {
patterns: state.config.patterns.filter(p => p !== action.recurrence),
},
};
case 'set-skip-weekend':
return {
...state,
config: {
...state.config,
skipWeekend: action.skipWeekend,
},
};
case 'set-weekend-solve':
return {
...state,
config: {
...state.config,
weekendSolveMode: action.value,
},
};
default:
return state;
}
@@ -254,6 +273,9 @@ function RecurringScheduleTooltip({ config: currentConfig, onClose, onSave }) {
config: parseConfig(currentConfig),
});
let skipWeekend = state.config.hasOwnProperty('skipWeekend')
? state.config.skipWeekend
: false;
let dateFormat = useSelector(
state => state.prefs.local.dateFormat || 'MM/dd/yyyy',
);
@@ -346,6 +368,56 @@ function RecurringScheduleTooltip({ config: currentConfig, onClose, onSave }) {
config.patterns.length > 0 && (
<MonthlyPatterns config={config} dispatch={dispatch} />
)}
<Stack direction="column" style={{ marginTop: 5 }}>
<View
style={{
marginTop: 5,
flex: 1,
flexDirection: 'row',
alignItems: 'center',
userSelect: 'none',
}}
>
<Checkbox
id="form_skipwe"
checked={skipWeekend}
onChange={e => {
dispatch({
type: 'set-skip-weekend',
skipWeekend: e.target.checked,
});
}}
/>
<label
htmlFor="form_skipwe"
style={{ userSelect: 'none', marginRight: 5 }}
>
Move schedule{' '}
</label>
<Select
id="solve_dropdown"
options={[
['before', 'before'],
['after', 'after'],
]}
value={state.config.weekendSolveMode}
onChange={value =>
dispatch({ type: 'set-weekend-solve', value: value })
}
style={{
minHeight: '1px',
width: '5rem',
}}
/>
<label
htmlFor="solve_dropdown"
style={{ userSelect: 'none', marginLeft: 5 }}
>
{' '}
weekend
</label>
</View>
</Stack>
<SchedulePreview previewDates={previewDates} />
<div
style={{ display: 'flex', marginTop: 15, justifyContent: 'flex-end' }}

View File

@@ -27,7 +27,13 @@ function parseRecurDate(desc) {
return {
type: 'recur',
schedule: new RSchedule({ rrules: rules }),
schedule: new RSchedule({
rrules: rules,
data: {
skipWeekend: desc.skipWeekend,
weekendSolve: desc.weekendSolveMode,
},
}),
};
} catch (e) {
throw new RuleError('parse-recur-date', e.message);

View File

@@ -84,6 +84,12 @@ export function getNextDate(dateCond, start = new Date()) {
if (dates.length > 0) {
let date = dates[0].date;
if (value.schedule.data.skipWeekend) {
date = getDateWithSkippedWeekend(
date,
value.schedule.data.weekendSolve,
);
}
return dayFromDate(date);
}
}
@@ -372,7 +378,12 @@ async function getUpcomingDates({ config, count }) {
return schedule
.occurrences({ start: d.startOfDay(new Date()), take: count })
.toArray()
.map(date => dayFromDate(date.date));
.map(date =>
config.skipWeekend
? getDateWithSkippedWeekend(date.date, config.weekendSolveMode)
: date.date,
)
.map(date => dayFromDate(date));
} catch (err) {
captureBreadcrumb(config);
throw err;
@@ -564,4 +575,17 @@ app.events.on('sync', ({ type, subtype }) => {
}
});
function getDateWithSkippedWeekend(date, solveMode) {
if (d.isWeekend(date)) {
if (solveMode === 'after') {
return d.nextMonday(date);
} else if (solveMode === 'before') {
return d.previousFriday(date);
} else {
throw new Error('Unknown weekend solve mode, this should not happen!');
}
}
return date;
}
export default app;

View File

@@ -0,0 +1,6 @@
---
category: Enhancements
authors: [pole95]
---
Allow schedules to skip weekends, and automatically reschedule to before or after the weekend.