diff --git a/src/app/features/tag/store/tag.reducer.ts b/src/app/features/tag/store/tag.reducer.ts index 936a084d1..343e53c84 100644 --- a/src/app/features/tag/store/tag.reducer.ts +++ b/src/app/features/tag/store/tag.reducer.ts @@ -11,7 +11,7 @@ import { TaskActionTypes, UpdateTaskTags } from '../../tasks/store/task.actions'; -import { TODAY_TAG } from '../tag.const'; +import { ALL_TAG, TODAY_TAG } from '../tag.const'; import { WorkContextType } from '../../work-context/work-context.model'; import { moveTaskDownInTodayList, @@ -67,19 +67,32 @@ export const initialTagState: TagState = tagAdapter.getInitialState({ // additional entity state properties }); -const _addMyDayTagIfNecessary = (state: TagState): TagState => { +const _addMyDayTagAndAllIfNecessary = (state: TagState): TagState => { const ids = state.ids as string[]; + let newState = state; if (ids && !ids.includes(TODAY_TAG.id)) { - return { - ...state, + newState = { + ...newState, ids: ([TODAY_TAG.id, ...ids] as string[]), entities: { - ...state.entities, + ...newState.entities, [TODAY_TAG.id]: TODAY_TAG, } }; } - return state; + + if (ids && !ids.includes(ALL_TAG.id)) { + newState = { + ...newState, + ids: ([ALL_TAG.id, ...ids] as string[]), + entities: { + ...newState.entities, + [ALL_TAG.id]: ALL_TAG, + } + }; + } + + return newState; }; const _reducer = createReducer( @@ -87,7 +100,7 @@ const _reducer = createReducer( // META ACTIONS // ------------ - on(loadAllData, (oldState, {appDataComplete}) => _addMyDayTagIfNecessary( + on(loadAllData, (oldState, {appDataComplete}) => _addMyDayTagAndAllIfNecessary( appDataComplete.tag ? {...appDataComplete.tag} : oldState) diff --git a/src/app/features/tag/tag.const.ts b/src/app/features/tag/tag.const.ts index 797c3c86e..479206954 100644 --- a/src/app/features/tag/tag.const.ts +++ b/src/app/features/tag/tag.const.ts @@ -21,6 +21,21 @@ export const TODAY_TAG: Tag = { } }; +export const ALL_TAG: Tag = { + id: 'ALL', + icon: 'wb_sunny', + title: 'All', + color: null, + created: Date.now(), + modified: Date.now(), + taskIds: [], + ...WORK_CONTEXT_DEFAULT_COMMON, + theme: { + ...WORK_CONTEXT_DEFAULT_THEME, + primary: DEFAULT_TODAY_TAG_COLOR, + } +}; + export const DEFAULT_TAG: Tag = { id: '', icon: null, diff --git a/src/app/features/tasks/store/task.selectors.ts b/src/app/features/tasks/store/task.selectors.ts index 1a0535b14..4757eb587 100644 --- a/src/app/features/tasks/store/task.selectors.ts +++ b/src/app/features/tasks/store/task.selectors.ts @@ -49,7 +49,7 @@ export const flattenTasks = (tasksIN: TaskWithSubTasks[]): TaskWithSubTasks[] => // SELECTORS // --------- -const {selectEntities, selectAll} = taskAdapter.getSelectors(); +const {selectEntities, selectAll, selectIds} = taskAdapter.getSelectors(); export const selectTaskFeatureState = createFeatureSelector(TASK_FEATURE_NAME); export const selectTaskEntities = createSelector(selectTaskFeatureState, selectEntities); export const selectCurrentTaskId = createSelector(selectTaskFeatureState, state => state.currentTaskId); @@ -113,6 +113,7 @@ export const selectCurrentTaskParentOrCurrent = createSelector(selectTaskFeature ); export const selectAllTasks = createSelector(selectTaskFeatureState, selectAll); +export const selectAllTaskIds = createSelector(selectTaskFeatureState, selectIds); export const selectScheduledTasks = createSelector(selectAllTasks, (tasks) => tasks.filter(task => task.reminderId)); export const selectAllTasksWithSubTasks = createSelector(selectAllTasks, mapSubTasksToTasks); diff --git a/src/app/features/work-context/work-context.service.ts b/src/app/features/work-context/work-context.service.ts index 6fe1c0012..13c342f9c 100644 --- a/src/app/features/work-context/work-context.service.ts +++ b/src/app/features/work-context/work-context.service.ts @@ -26,13 +26,18 @@ import { take, withLatestFrom } from 'rxjs/operators'; -import { TODAY_TAG } from '../tag/tag.const'; +import { ALL_TAG, TODAY_TAG } from '../tag/tag.const'; import { TagService } from '../tag/tag.service'; import { Task, TaskWithSubTasks } from '../tasks/task.model'; import { distinctUntilChangedObject } from '../../util/distinct-until-changed-object'; import { getWorklogStr } from '../../util/get-work-log-str'; import { hasTasksToWorkOn, mapEstimateRemainingFromTasks } from './work-context.util'; -import { flattenTasks, selectTaskEntities, selectTasksWithSubTasksByIds } from '../tasks/store/task.selectors'; +import { + flattenTasks, + selectAllTaskIds, + selectTaskEntities, + selectTasksWithSubTasksByIds +} from '../tasks/store/task.selectors'; import { Actions, ofType } from '@ngrx/effects'; import { moveTaskToBacklogList } from './store/work-context-meta.actions'; import { selectProjectById } from '../project/store/project.reducer'; @@ -108,6 +113,30 @@ export class WorkContextService { activeWorkContext$: Observable = this.activeWorkContextTypeAndId$.pipe( switchMap(({activeId, activeType}) => { if (activeType === WorkContextType.TAG) { + if (activeId === ALL_TAG.id) { + return this._store$.pipe(select(selectAllTaskIds)).pipe( + take(1), + switchMap((allIds: string[] = []) => this._tagService.getTagById$(activeId).pipe( + // TODO find out why this is sometimes undefined + filter(p => !!p), + map(tag => { + const ids = [ + // existing list without removed ones + ...tag.taskIds.filter(tagId => allIds.includes(tagId)), + // all without already existing list ones + ...allIds.filter(tagId => !tag.taskIds.includes(tagId)) + ]; + return { + ...tag, + type: WorkContextType.TAG, + routerLink: `tag/${tag.id}`, + taskIds: ids, + }; + } + )) + ) + ); + } return this._tagService.getTagById$(activeId).pipe( // TODO find out why this is sometimes undefined filter(p => !!p),