super-productivity/src/app/plugins/plugin-hooks.effects.ts

251 lines
7.4 KiB
TypeScript

import { inject, Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { select, Store } from '@ngrx/store';
import { filter, map, switchMap, take, tap, withLatestFrom } from 'rxjs/operators';
import { EMPTY } from 'rxjs';
import {
selectTaskById,
selectTaskFeatureState,
} from '../features/tasks/store/task.selectors';
import { selectProjectFeatureState } from '../features/project/store/project.selectors';
import { Task } from '../features/tasks/task.model';
import { PluginService } from './plugin.service';
import { PluginHooks } from './plugin-api.model';
import { setActiveWorkContext } from '../features/work-context/store/work-context.actions';
import { TaskSharedActions } from '../root-store/meta/task-shared.actions';
import {
setCurrentTask,
unsetCurrentTask,
moveSubTask,
moveSubTaskUp,
moveSubTaskDown,
moveSubTaskToTop,
moveSubTaskToBottom,
} from '../features/tasks/store/task.actions';
import * as projectActions from '../features/project/store/project.actions';
import { updateProject } from '../features/project/store/project.actions';
import {
moveTaskDownInTodayList,
moveTaskInTodayList,
moveTaskToBottomInTodayList,
moveTaskToTopInTodayList,
moveTaskUpInTodayList,
} from '../features/work-context/store/work-context-meta.actions';
@Injectable()
export class PluginHooksEffects {
private readonly actions$ = inject(Actions);
private readonly store = inject(Store);
private readonly pluginService = inject(PluginService);
taskComplete$ = createEffect(
() =>
this.actions$.pipe(
ofType(TaskSharedActions.updateTask),
filter((action) => action.task.changes.isDone === true),
switchMap((action) =>
this.store.pipe(
select(selectTaskById, { id: action.task.id as string }),
take(1),
tap((task: Task | undefined) => {
if (task) {
this.pluginService.dispatchHook(PluginHooks.TASK_COMPLETE, task);
}
}),
map(() => EMPTY),
),
),
),
{ dispatch: false },
);
onCurrentTaskChange$ = createEffect(
() =>
this.actions$.pipe(
ofType(setCurrentTask, unsetCurrentTask),
withLatestFrom(this.store.pipe(select(selectTaskFeatureState))),
map(([action, taskState]) => {
this.pluginService.dispatchHook(
PluginHooks.CURRENT_TASK_CHANGE,
taskState.currentTaskId,
);
}),
),
{ dispatch: false },
);
taskUpdate$ = createEffect(
() =>
this.actions$.pipe(
ofType(TaskSharedActions.updateTask),
switchMap((action) =>
this.store.pipe(
select(selectTaskById, { id: action.task.id as string }),
take(1),
tap((task: Task | undefined) => {
if (task) {
this.pluginService.dispatchHook(PluginHooks.TASK_UPDATE, task);
}
}),
map(() => EMPTY),
),
),
),
{ dispatch: false },
);
taskDelete$ = createEffect(
() =>
this.actions$.pipe(
ofType(TaskSharedActions.deleteTask),
tap((action) => {
this.pluginService.dispatchHook(PluginHooks.TASK_DELETE, {
taskId: action.task.id,
});
}),
),
{ dispatch: false },
);
tasksDelete$ = createEffect(
() =>
this.actions$.pipe(
ofType(TaskSharedActions.deleteTasks),
tap((action) => {
this.pluginService.dispatchHook(PluginHooks.TASK_DELETE, {
taskIds: action.taskIds,
});
}),
),
{ dispatch: false },
);
taskAdd$ = createEffect(
() =>
this.actions$.pipe(
ofType(TaskSharedActions.addTask),
switchMap((action) =>
this.store.pipe(
select(selectTaskById, { id: action.task.id }),
take(1),
filter((task) => !!task),
tap((task: Task | undefined) => {
if (task) {
this.pluginService.dispatchHook(PluginHooks.TASK_UPDATE, task);
}
}),
map(() => EMPTY),
),
),
),
{ dispatch: false },
);
workContextChange$ = createEffect(
() =>
this.actions$.pipe(
ofType(setActiveWorkContext),
tap((action) => {
this.pluginService.dispatchHook(PluginHooks.LANGUAGE_CHANGE, {
activeId: action.activeId,
activeType: action.activeType,
});
}),
),
{ dispatch: false },
);
finishDay$ = createEffect(
() =>
this.actions$.pipe(
filter((action) => action.type === 'FINISH_DAY'),
tap(() => {
this.pluginService.dispatchHook(PluginHooks.FINISH_DAY);
}),
),
{ dispatch: false },
);
// Trigger for ANY task update (add, update, delete, move subtasks)
anyTaskUpdate$ = createEffect(
() =>
this.actions$.pipe(
ofType(
TaskSharedActions.addTask,
TaskSharedActions.updateTask,
TaskSharedActions.deleteTask,
TaskSharedActions.deleteTasks,
// Include subtask move actions
moveSubTask,
moveSubTaskUp,
moveSubTaskDown,
moveSubTaskToTop,
moveSubTaskToBottom,
),
withLatestFrom(this.store.pipe(select(selectTaskFeatureState))),
tap(([action, taskState]) => {
this.pluginService.dispatchHook(PluginHooks.ANY_TASK_UPDATE, {
action: action.type,
taskState,
});
}),
),
{ dispatch: false },
);
// Trigger when project taskIds or backlogTaskIds change
projectListUpdate$ = createEffect(
() =>
this.actions$.pipe(
ofType(
// Direct project updates
updateProject,
// Task-related actions that affect project lists
TaskSharedActions.addTask,
TaskSharedActions.deleteTask,
TaskSharedActions.deleteTasks,
TaskSharedActions.moveToOtherProject,
// Project task list actions
projectActions.moveProjectTaskToBacklogListAuto,
projectActions.moveProjectTaskToRegularListAuto,
projectActions.moveProjectTaskUpInBacklogList,
projectActions.moveProjectTaskDownInBacklogList,
projectActions.moveProjectTaskToTopInBacklogList,
projectActions.moveProjectTaskToBottomInBacklogList,
projectActions.moveProjectTaskInBacklogList,
projectActions.moveProjectTaskToBacklogList,
projectActions.moveProjectTaskToRegularList,
projectActions.moveAllProjectBacklogTasksToRegularList,
// cross model
moveTaskInTodayList,
moveTaskUpInTodayList,
moveTaskDownInTodayList,
moveTaskToTopInTodayList,
moveTaskToBottomInTodayList,
),
withLatestFrom(this.store.pipe(select(selectProjectFeatureState))),
tap(([action, projectState]) => {
this.pluginService.dispatchHook(PluginHooks.PROJECT_LIST_UPDATE, {
action: action.type,
projectState,
});
}),
),
{ dispatch: false },
);
// private static hiddenActions = [];
anyAction$ = createEffect(
() =>
this.actions$.pipe(
tap((action) => {
this.pluginService.dispatchHook(PluginHooks.ACTION, {
action,
});
}),
),
{ dispatch: false },
);
}