mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-23 02:36:05 +00:00
fix(recurring-tasks): show overdue recurring tasks in Today view #4825
- Changed addAllDueToday() to use getRepeatableTasksDueForDayIncludingOverdue$ - This ensures overdue recurring tasks (e.g., weekly tasks missed for several days) appear in Today view - Added comprehensive unit tests for overdue recurring task scenarios - Users can now see and access overdue recurring tasks when returning after missing days Fixes #4825
This commit is contained in:
parent
29c55bf956
commit
47fb1b61b1
2 changed files with 83 additions and 3 deletions
|
|
@ -132,6 +132,7 @@ describe('AddTasksForTomorrowService', () => {
|
|||
beforeEach(() => {
|
||||
taskRepeatCfgServiceMock = jasmine.createSpyObj('TaskRepeatCfgService', [
|
||||
'getRepeatableTasksDueForDayOnly$',
|
||||
'getRepeatableTasksDueForDayIncludingOverdue$',
|
||||
'createRepeatableTask',
|
||||
]);
|
||||
|
||||
|
|
@ -144,6 +145,9 @@ describe('AddTasksForTomorrowService', () => {
|
|||
|
||||
// Configure mock return values
|
||||
taskRepeatCfgServiceMock.getRepeatableTasksDueForDayOnly$.and.returnValue(of([]));
|
||||
taskRepeatCfgServiceMock.getRepeatableTasksDueForDayIncludingOverdue$.and.returnValue(
|
||||
of([]),
|
||||
);
|
||||
taskRepeatCfgServiceMock.createRepeatableTask.and.returnValue(Promise.resolve());
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
|
|
@ -350,7 +354,7 @@ describe('AddTasksForTomorrowService', () => {
|
|||
|
||||
describe('addAllDueToday()', () => {
|
||||
it('should create repeatable tasks for today but not dispatch if no tasks to move', async () => {
|
||||
taskRepeatCfgServiceMock.getRepeatableTasksDueForDayOnly$.and.returnValue(
|
||||
taskRepeatCfgServiceMock.getRepeatableTasksDueForDayIncludingOverdue$.and.returnValue(
|
||||
of([mockRepeatCfg, mockRepeatCfg2]),
|
||||
);
|
||||
store.overrideSelector(selectTasksWithDueTimeForRange, []);
|
||||
|
|
@ -369,7 +373,9 @@ describe('AddTasksForTomorrowService', () => {
|
|||
});
|
||||
|
||||
it('should add due tasks to today', async () => {
|
||||
taskRepeatCfgServiceMock.getRepeatableTasksDueForDayOnly$.and.returnValue(of([]));
|
||||
taskRepeatCfgServiceMock.getRepeatableTasksDueForDayIncludingOverdue$.and.returnValue(
|
||||
of([]),
|
||||
);
|
||||
store.overrideSelector(selectTasksWithDueTimeForRange, [mockTaskWithDueTimeToday]);
|
||||
store.overrideSelector(selectTasksDueForDay, [mockTaskWithDueDayToday]);
|
||||
store.overrideSelector(selectTasksForPlannerDay(getWorklogStr(today)), [
|
||||
|
|
@ -395,6 +401,80 @@ describe('AddTasksForTomorrowService', () => {
|
|||
expect(actualCall.taskIds).toContain('task4');
|
||||
expect(result).toBe('ADDED');
|
||||
});
|
||||
|
||||
it('should include overdue recurring tasks from previous days', async () => {
|
||||
const overdueWeeklyTask: TaskRepeatCfg = {
|
||||
...mockRepeatCfg,
|
||||
id: 'overdue-weekly',
|
||||
title: 'Weekly task from last Thursday',
|
||||
repeatCycle: 'WEEKLY',
|
||||
repeatEvery: 1,
|
||||
startDate: '2024-01-01', // Started months ago
|
||||
lastTaskCreation: new Date('2024-01-01').getTime(), // Last created months ago
|
||||
};
|
||||
|
||||
taskRepeatCfgServiceMock.getRepeatableTasksDueForDayIncludingOverdue$.and.returnValue(
|
||||
of([overdueWeeklyTask]),
|
||||
);
|
||||
store.overrideSelector(selectTasksWithDueTimeForRange, []);
|
||||
store.overrideSelector(selectTasksDueForDay, []);
|
||||
store.overrideSelector(selectTasksForPlannerDay(getWorklogStr(today)), []);
|
||||
store.overrideSelector(selectTodayTaskIds, []);
|
||||
const dispatchSpy = spyOn(store, 'dispatch');
|
||||
|
||||
const result = await service.addAllDueToday();
|
||||
|
||||
expect(taskRepeatCfgServiceMock.createRepeatableTask).toHaveBeenCalledWith(
|
||||
overdueWeeklyTask,
|
||||
jasmine.any(Number),
|
||||
);
|
||||
expect(taskRepeatCfgServiceMock.createRepeatableTask).toHaveBeenCalledTimes(1);
|
||||
// No dispatch since only repeatable tasks were created, no existing tasks to move
|
||||
expect(dispatchSpy).not.toHaveBeenCalled();
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle multiple overdue recurring tasks', async () => {
|
||||
const overdueDaily: TaskRepeatCfg = {
|
||||
...mockRepeatCfg,
|
||||
id: 'overdue-daily',
|
||||
title: 'Daily task from 3 days ago',
|
||||
repeatCycle: 'DAILY',
|
||||
repeatEvery: 1,
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
lastTaskCreation: Date.now() - 4 * 24 * 60 * 60 * 1000, // 4 days ago
|
||||
};
|
||||
|
||||
const overdueMonthly: TaskRepeatCfg = {
|
||||
...mockRepeatCfg,
|
||||
id: 'overdue-monthly',
|
||||
title: 'Monthly task from last month',
|
||||
repeatCycle: 'MONTHLY',
|
||||
repeatEvery: 1,
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
lastTaskCreation: Date.now() - 35 * 24 * 60 * 60 * 1000, // 35 days ago
|
||||
};
|
||||
|
||||
taskRepeatCfgServiceMock.getRepeatableTasksDueForDayIncludingOverdue$.and.returnValue(
|
||||
of([overdueDaily, overdueMonthly]),
|
||||
);
|
||||
store.overrideSelector(selectTasksWithDueTimeForRange, []);
|
||||
store.overrideSelector(selectTasksDueForDay, []);
|
||||
store.overrideSelector(selectTasksForPlannerDay(getWorklogStr(today)), []);
|
||||
store.overrideSelector(selectTodayTaskIds, []);
|
||||
|
||||
await service.addAllDueToday();
|
||||
|
||||
expect(taskRepeatCfgServiceMock.createRepeatableTask).toHaveBeenCalledTimes(2);
|
||||
expect(taskRepeatCfgServiceMock.createRepeatableTask).toHaveBeenCalledWith(
|
||||
overdueDaily,
|
||||
jasmine.any(Number),
|
||||
);
|
||||
expect(taskRepeatCfgServiceMock.createRepeatableTask).toHaveBeenCalledWith(
|
||||
overdueMonthly,
|
||||
jasmine.any(Number),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_sortAll()', () => {
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ export class AddTasksForTomorrowService {
|
|||
TaskLog.log('[AddTasksForTomorrow] Starting addAllDueToday', { todayStr });
|
||||
|
||||
const dueRepeatCfgs = await this._taskRepeatCfgService
|
||||
.getRepeatableTasksDueForDayOnly$(todayDate.getTime())
|
||||
.getRepeatableTasksDueForDayIncludingOverdue$(todayDate.getTime())
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue