Skip to content

Commit

Permalink
feat(tasks): move all selection logic to selectors
Browse files Browse the repository at this point in the history
  • Loading branch information
johannesjo committed Oct 23, 2018
1 parent 0f10606 commit 16dca90
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 64 deletions.
13 changes: 13 additions & 0 deletions src/app/issue/issue.selector.ts
@@ -0,0 +1,13 @@
import { createSelector } from '@ngrx/store';
import { selectJiraIssueEntities } from './jira/jira-issue/store/jira-issue.reducer';

export const selectIssueEntityMap = createSelector(
selectJiraIssueEntities,
(
(jiraIssues) => {
return {
JIRA: jiraIssues
};
}
)
);
15 changes: 2 additions & 13 deletions src/app/issue/issue.service.ts
@@ -1,24 +1,13 @@
import { map } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { JiraIssueService } from './jira/jira-issue/jira-issue.service';
import { combineLatest, Observable } from 'rxjs';
import { IssueEntityMap, IssueProviderKey } from './issue';
import { IssueProviderKey } from './issue';
import { JiraIssueContentComponent } from './jira/jira-issue/jira-issue-content/jira-issue-content.component';
import { JiraIssueHeaderComponent } from './jira/jira-issue/jira-issue-header/jira-issue-header.component';

@Injectable({
providedIn: 'root'
})
export class IssueService {
public issueEntityMap$: Observable<IssueEntityMap> = combineLatest(
this._jiraIssueService.jiraIssuesEntities$
).pipe(map(([jiraEntities]) => {
return {
JIRA: jiraEntities
};
}));

constructor(private _jiraIssueService: JiraIssueService) {
constructor() {
}

public getTabHeader(issueType: IssueProviderKey) {
Expand Down
4 changes: 2 additions & 2 deletions src/app/issue/jira/jira-issue/store/jira-issue.reducer.ts
Expand Up @@ -3,8 +3,9 @@ import { JiraIssueActions, JiraIssueActionTypes } from './jira-issue.actions';
import { JiraIssue } from '../jira-issue.model';
import { createFeatureSelector, createSelector } from '@ngrx/store';
import { TaskActionTypes } from '../../../../tasks/store/task.actions';
import { IssueProviderKey } from '../../../issue';

export const JIRA_ISSUE_FEATURE_NAME = 'issues';
export const JIRA_ISSUE_FEATURE_NAME: IssueProviderKey = 'JIRA';

export interface JiraIssueState extends EntityState<JiraIssue> {
// additional entities state properties
Expand All @@ -13,7 +14,6 @@ export interface JiraIssueState extends EntityState<JiraIssue> {

export const jiraIssueAdapter: EntityAdapter<JiraIssue> = createEntityAdapter<JiraIssue>();


// SELECTORS
// ---------
export const selectJiraIssueFeatureState = createFeatureSelector<JiraIssueState>(JIRA_ISSUE_FEATURE_NAME);
Expand Down
2 changes: 1 addition & 1 deletion src/app/tasks/add-task-bar/add-task-bar.component.ts
Expand Up @@ -70,7 +70,7 @@ export class AddTaskBarComponent implements OnInit, OnDestroy {
console.log(issueOrTitle);

if (typeof issueOrTitle === 'string') {
this._taskService.add(issueOrTitle,true);
this._taskService.add(issueOrTitle);
} else {
this._taskService.addWithIssue(
issueOrTitle.summary,
Expand Down
50 changes: 40 additions & 10 deletions src/app/tasks/store/task.reducer.ts
Expand Up @@ -3,6 +3,8 @@ import { TaskActions, TaskActionTypes } from './task.actions';
import { Task } from '../task.model';
import { createFeatureSelector, createSelector } from '@ngrx/store';
import { calcTotalTimeSpent } from '../util/calc-total-time-spent';
import { selectIssueEntityMap } from '../../issue/issue.selector';
import { tasks } from 'googleapis/build/src/apis/tasks';

export const TASK_FEATURE_NAME = 'tasks';

Expand All @@ -23,25 +25,53 @@ export interface TaskState extends EntityState<Task> {

export const taskAdapter: EntityAdapter<Task> = createEntityAdapter<Task>();

const mapIssueDataToTask = (tasks_, issueEntityMap) => {
return tasks_ && tasks_.map((task) => {
const issueData = (task.issueId && task.issueType) && issueEntityMap[task.issueType][task.issueId];
return issueData ? {...task, issueData: issueData} : task;
});
};

const mapSubTasksToTasks = (tasks__) => {
return tasks__.filter((task) => !task.parentId)
.map((task) => {
if (task.subTaskIds && task.subTaskIds.length > 0) {
return {
...task,
subTasks: task.subTaskIds
.map((subTaskId) => {
return tasks__.find((task_) => task_.id === subTaskId);
})
// filter out undefined
// .filter((subTask) => !!subTask)
};
} else {
return task;
}
});
};

const mapTasksFromIds = (tasks__, ids) => {
return ids.map(id => tasks__.find(task => task.id === id));
};

// SELECTORS
// ---------
const {selectIds, selectEntities, selectAll, selectTotal} = taskAdapter.getSelectors();
export const selectTaskFeatureState = createFeatureSelector<TaskState>(TASK_FEATURE_NAME);
export const selectBacklogTaskIds = createSelector(selectTaskFeatureState, state => state.backlogTaskIds);
export const selectTodaysTaskIds = createSelector(selectTaskFeatureState, state => state.todaysTaskIds);
export const selectCurrentTask = createSelector(selectTaskFeatureState, state => state.currentTaskId);

const {selectIds, selectEntities, selectAll, selectTotal} = taskAdapter.getSelectors();

export const selectAllTasks = createSelector(selectTaskFeatureState, selectAll);
export const selectAllTasksWithIssueData = createSelector(selectAllTasks, selectIssueEntityMap, mapIssueDataToTask);

// export const selectAllTasksWithIssueData = createSelector((state) => {
// const tasks = state[TASK_FEATURE_NAME];
// const issues = state[JIRA_ISSUE_FEATURE_NAME];
// return state.tasks;
// });
// const selectBacklogTasks = createSelector(selectTaskFeatureState, (state) => state.backlogTaskIds.map(id => state.entities[id]));
export const selectAllTasksWithSubTasks = createSelector(selectAllTasksWithIssueData, mapSubTasksToTasks);

export const selectCurrentTask = createSelector(selectTaskFeatureState, state => state.currentTaskId);
export const selectBacklogTaskIds = createSelector(selectTaskFeatureState, state => state.backlogTaskIds);
export const selectTodaysTaskIds = createSelector(selectTaskFeatureState, state => state.todaysTaskIds);
export const selectTodaysTasksWithSubTasks = createSelector(selectAllTasksWithSubTasks, selectTodaysTaskIds, mapTasksFromIds);

export const selectBacklogTasksWithSubTasks = createSelector(selectAllTasksWithSubTasks, selectBacklogTaskIds, mapTasksFromIds);


// REDUCER
Expand Down
51 changes: 13 additions & 38 deletions src/app/tasks/task.service.ts
Expand Up @@ -5,56 +5,31 @@ import { Task, TaskWithSubTasks } from './task.model';
import { select, Store } from '@ngrx/store';
import { TaskActionTypes } from './store/task.actions';
import shortid from 'shortid';
import { initialTaskState, selectAllTasks, selectCurrentTask } from './store/task.reducer';
import {
initialTaskState,
selectAllTasksWithSubTasks,
selectBacklogTasksWithSubTasks,
selectCurrentTask,
selectTodaysTasksWithSubTasks,
} from './store/task.reducer';
import { ProjectService } from '../project/project.service';
import { PersistenceService } from '../core/persistence/persistence.service';
import { IssueService } from '../issue/issue.service';
import { IssueProviderKey } from '../issue/issue';
import { TimeTrackingService } from '../core/time-tracking/time-tracking.service';
import { Tick } from '../core/time-tracking/time-tracking';

const mapIssueDataToTasks = map(([tasks, issueEntityMap]) => tasks.map((task) => {
const issueData = (task.issueId && task.issueType) && issueEntityMap[task.issueType][task.issueId];
return issueData ? {...task, issueData: issueData} : task;
}));

const mapSubTasksToTasks = map(tasks => {
return tasks.filter((task) => !task.parentId)
.map((task) => {
if (task.subTaskIds && task.subTaskIds.length > 0) {
return {
...task,
subTasks: task.subTaskIds
.map((subTaskId) => {
return tasks.find((task_) => task_.id === subTaskId);
})
// filter out undefined
// .filter((subTask) => !!subTask)
};
} else {
return task;
}
});
});


@Injectable()
export class TaskService {
currentTaskId$: Observable<string> = this._store.pipe(select(selectCurrentTask));

tasks$: Observable<TaskWithSubTasks[]> = combineLatest(
this._store.pipe(select(selectAllTasks)),
this._issueService.issueEntityMap$
).pipe(mapIssueDataToTasks, mapSubTasksToTasks);
tasks$: Observable<TaskWithSubTasks[]> = this._store.pipe(select(selectAllTasksWithSubTasks));

backlogTasks$: Observable<TaskWithSubTasks[]> =
this.tasks$.pipe(map(
(tasks) => tasks && tasks.filter((task: TaskWithSubTasks) => task.isBacklogTask)
));
todaysTasks$: Observable<TaskWithSubTasks[]> = this._store.pipe(select(selectTodaysTasksWithSubTasks));

backlogTasks$: Observable<TaskWithSubTasks[]> = this._store.pipe(select(selectBacklogTasksWithSubTasks));

todaysTasks$: Observable<TaskWithSubTasks[]> = this.tasks$.pipe(map(
(tasks) => tasks && tasks.filter((task: TaskWithSubTasks) => !task.isBacklogTask)
));

undoneTasks$: Observable<TaskWithSubTasks[]> = this.todaysTasks$.pipe(map(
(tasks) => tasks && tasks.filter((task: TaskWithSubTasks) => !task.isDone)
Expand Down Expand Up @@ -104,7 +79,7 @@ export class TaskService {
private readonly _persistenceService: PersistenceService,
private readonly _timeTrackingService: TimeTrackingService,
) {
// this.test$.subscribe((val) => console.log(val));
this.todaysTasks$.subscribe((val) => console.log(val));
this.missingIssuesForTasks$.subscribe((val) => {
if (val && val.length > 0) {
console.error('MISSING ISSUE', val);
Expand Down Expand Up @@ -156,7 +131,7 @@ export class TaskService {

// Tasks
// -----
add(title: string, isAddToBacklog = true) {
add(title: string, isAddToBacklog = false) {
this._store.dispatch({
type: TaskActionTypes.AddTask,
payload: {
Expand Down

0 comments on commit 16dca90

Please sign in to comment.