2020-04-20 11:14:46 +02:00
|
|
|
import { Project } from "../models/project";
|
2020-04-21 20:45:47 +02:00
|
|
|
import { Task, TaskID, EstimationConfidence, TaskCategoryID, TaskCategory } from "../models/task";
|
2020-07-09 13:00:42 +02:00
|
|
|
import { useReducer } from "react";
|
2020-05-03 18:34:44 +02:00
|
|
|
import { generate as diff } from "json-merge-patch";
|
|
|
|
import { applyPatch } from "../util/patch";
|
|
|
|
|
2020-04-20 11:14:46 +02:00
|
|
|
|
|
|
|
export interface Action {
|
2020-05-03 18:34:44 +02:00
|
|
|
type: string
|
2020-04-20 11:14:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export type ProjectReducerActions =
|
2020-05-03 18:34:44 +02:00
|
|
|
AddTask |
|
|
|
|
RemoveTask |
|
|
|
|
UpdateTaskEstimation |
|
|
|
|
UpdateProjectLabel |
|
|
|
|
UpdateTaskLabel |
|
|
|
|
UpdateParam |
|
|
|
|
UpdateTaskCategoryLabel |
|
|
|
|
UpdateTaskCategoryCost |
|
|
|
|
AddTaskCategory |
|
|
|
|
RemoveTaskCategory |
|
|
|
|
PatchProject
|
2020-04-20 11:14:46 +02:00
|
|
|
|
2020-04-20 14:07:26 +02:00
|
|
|
export function useProjectReducer(project: Project) {
|
2020-05-03 18:34:44 +02:00
|
|
|
return useReducer(projectReducer, project);
|
2020-04-20 14:07:26 +02:00
|
|
|
}
|
|
|
|
|
2020-04-20 11:14:46 +02:00
|
|
|
export function projectReducer(project: Project, action: ProjectReducerActions): Project {
|
2020-05-03 18:34:44 +02:00
|
|
|
console.log(action);
|
|
|
|
switch(action.type) {
|
|
|
|
case ADD_TASK:
|
|
|
|
return handleAddTask(project, action as AddTask);
|
|
|
|
|
|
|
|
case REMOVE_TASK:
|
|
|
|
return handleRemoveTask(project, action as RemoveTask);
|
|
|
|
|
|
|
|
case UPDATE_TASK_ESTIMATION:
|
|
|
|
return handleUpdateTaskEstimation(project, action as UpdateTaskEstimation);
|
|
|
|
|
|
|
|
case UPDATE_PROJECT_LABEL:
|
|
|
|
return handleUpdateProjectLabel(project, action as UpdateProjectLabel);
|
|
|
|
|
|
|
|
case UPDATE_TASK_LABEL:
|
|
|
|
return handleUpdateTaskLabel(project, action as UpdateTaskLabel);
|
|
|
|
|
|
|
|
case UPDATE_PARAM:
|
|
|
|
return handleUpdateParam(project, action as UpdateParam);
|
|
|
|
|
|
|
|
case ADD_TASK_CATEGORY:
|
|
|
|
return handleAddTaskCategory(project, action as AddTaskCategory);
|
|
|
|
|
|
|
|
case REMOVE_TASK_CATEGORY:
|
|
|
|
return handleRemoveTaskCategory(project, action as RemoveTaskCategory);
|
|
|
|
|
|
|
|
case UPDATE_TASK_CATEGORY_LABEL:
|
|
|
|
return handleUpdateTaskCategoryLabel(project, action as UpdateTaskCategoryLabel);
|
|
|
|
|
|
|
|
case UPDATE_TASK_CATEGORY_COST:
|
|
|
|
return handleUpdateTaskCategoryCost(project, action as UpdateTaskCategoryCost);
|
|
|
|
|
|
|
|
case PATCH_PROJECT:
|
|
|
|
return handlePatchProject(project, action as PatchProject);
|
|
|
|
}
|
|
|
|
|
|
|
|
return project;
|
2020-04-20 11:14:46 +02:00
|
|
|
}
|
|
|
|
|
2020-04-21 09:24:39 +02:00
|
|
|
export interface AddTask extends Action {
|
2020-05-03 18:34:44 +02:00
|
|
|
task: Task
|
2020-04-20 11:14:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export const ADD_TASK = "ADD_TASK";
|
|
|
|
|
2020-04-21 09:24:39 +02:00
|
|
|
export function addTask(task: Task): AddTask {
|
2020-05-03 18:34:44 +02:00
|
|
|
return { type: ADD_TASK, task };
|
2020-04-20 11:14:46 +02:00
|
|
|
}
|
|
|
|
|
2020-04-21 09:24:39 +02:00
|
|
|
export function handleAddTask(project: Project, action: AddTask): Project {
|
2020-05-03 18:34:44 +02:00
|
|
|
const task = { ...action.task };
|
|
|
|
return {
|
|
|
|
...project,
|
|
|
|
tasks: {
|
|
|
|
...project.tasks,
|
|
|
|
[task.id]: task,
|
2023-09-01 05:56:07 +02:00
|
|
|
},
|
|
|
|
updatedAt: new Date(),
|
2020-05-03 18:34:44 +02:00
|
|
|
};
|
2020-04-21 09:24:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface RemoveTask extends Action {
|
2020-05-03 18:34:44 +02:00
|
|
|
id: TaskID
|
2020-04-20 11:14:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export const REMOVE_TASK = "REMOVE_TASK";
|
|
|
|
|
2020-04-21 09:24:39 +02:00
|
|
|
export function removeTask(id: TaskID): RemoveTask {
|
2020-05-03 18:34:44 +02:00
|
|
|
return { type: REMOVE_TASK, id };
|
2020-04-20 11:14:46 +02:00
|
|
|
}
|
|
|
|
|
2020-04-21 09:24:39 +02:00
|
|
|
export function handleRemoveTask(project: Project, action: RemoveTask): Project {
|
2020-05-03 18:34:44 +02:00
|
|
|
const tasks = { ...project.tasks };
|
|
|
|
delete tasks[action.id];
|
|
|
|
return {
|
|
|
|
...project,
|
2023-09-01 05:56:07 +02:00
|
|
|
tasks,
|
|
|
|
updatedAt: new Date(),
|
2020-05-03 18:34:44 +02:00
|
|
|
};
|
2020-04-21 09:24:39 +02:00
|
|
|
}
|
|
|
|
|
2020-04-20 11:14:46 +02:00
|
|
|
export interface UpdateTaskEstimation extends Action {
|
2020-05-03 18:34:44 +02:00
|
|
|
id: TaskID
|
|
|
|
confidence: string
|
|
|
|
value: number
|
2020-04-20 11:14:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export const UPDATE_TASK_ESTIMATION = "UPDATE_TASK_ESTIMATION";
|
|
|
|
|
|
|
|
export function updateTaskEstimation(id: TaskID, confidence: EstimationConfidence, value: number): UpdateTaskEstimation {
|
2020-05-03 18:34:44 +02:00
|
|
|
return { type: UPDATE_TASK_ESTIMATION, id, confidence, value };
|
2020-04-21 09:24:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export function handleUpdateTaskEstimation(project: Project, action: UpdateTaskEstimation): Project {
|
2020-05-03 18:34:44 +02:00
|
|
|
const estimations = {
|
|
|
|
...project.tasks[action.id].estimations,
|
|
|
|
[action.confidence]: action.value
|
|
|
|
};
|
|
|
|
|
|
|
|
return {
|
|
|
|
...project,
|
|
|
|
tasks: {
|
|
|
|
...project.tasks,
|
|
|
|
[action.id]: {
|
|
|
|
...project.tasks[action.id],
|
|
|
|
estimations: estimations,
|
2023-09-01 05:56:07 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
updatedAt: new Date(),
|
2020-05-03 18:34:44 +02:00
|
|
|
};
|
2020-04-21 09:24:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface UpdateProjectLabel extends Action {
|
2020-05-03 18:34:44 +02:00
|
|
|
label: string
|
2020-04-21 09:24:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export const UPDATE_PROJECT_LABEL = "UPDATE_PROJECT_LABEL";
|
|
|
|
|
|
|
|
export function updateProjectLabel(label: string): UpdateProjectLabel {
|
2020-05-03 18:34:44 +02:00
|
|
|
return { type: UPDATE_PROJECT_LABEL, label };
|
2020-04-21 09:24:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export function handleUpdateProjectLabel(project: Project, action: UpdateProjectLabel): Project {
|
2020-05-03 18:34:44 +02:00
|
|
|
return {
|
|
|
|
...project,
|
2023-09-01 05:56:07 +02:00
|
|
|
label: action.label,
|
|
|
|
updatedAt: new Date(),
|
2020-05-03 18:34:44 +02:00
|
|
|
};
|
2020-04-21 09:24:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface UpdateTaskLabel extends Action {
|
2020-05-03 18:34:44 +02:00
|
|
|
id: TaskID
|
|
|
|
label: string
|
2020-04-21 09:24:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export const UPDATE_TASK_LABEL = "UPDATE_TASK_LABEL";
|
|
|
|
|
|
|
|
export function updateTaskLabel(id: TaskID, label: string): UpdateTaskLabel {
|
2020-05-03 18:34:44 +02:00
|
|
|
return { type: UPDATE_TASK_LABEL, id, label };
|
2020-04-21 09:24:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export function handleUpdateTaskLabel(project: Project, action: UpdateTaskLabel): Project {
|
2020-05-03 18:34:44 +02:00
|
|
|
return {
|
|
|
|
...project,
|
|
|
|
tasks: {
|
|
|
|
...project.tasks,
|
|
|
|
[action.id]: {
|
|
|
|
...project.tasks[action.id],
|
|
|
|
label: action.label,
|
|
|
|
}
|
2023-09-01 05:56:07 +02:00
|
|
|
},
|
|
|
|
updatedAt: new Date(),
|
2020-05-03 18:34:44 +02:00
|
|
|
};
|
2020-04-21 20:45:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface UpdateParam extends Action {
|
2020-05-03 18:34:44 +02:00
|
|
|
name: string
|
|
|
|
value: any
|
2020-04-21 20:45:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export const UPDATE_PARAM = "UPDATE_PARAM";
|
|
|
|
|
|
|
|
export function updateParam(name: string, value: any): UpdateParam {
|
2020-05-03 18:34:44 +02:00
|
|
|
return { type: UPDATE_PARAM, name, value };
|
2020-04-21 20:45:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export function handleUpdateParam(project: Project, action: UpdateParam): Project {
|
2020-05-03 18:34:44 +02:00
|
|
|
return {
|
|
|
|
...project,
|
|
|
|
params: {
|
|
|
|
...project.params,
|
|
|
|
[action.name]: action.value,
|
2023-09-01 05:56:07 +02:00
|
|
|
},
|
|
|
|
updatedAt: new Date(),
|
2020-05-03 18:34:44 +02:00
|
|
|
};
|
2020-04-21 20:45:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface UpdateTaskCategoryLabel extends Action {
|
2020-05-03 18:34:44 +02:00
|
|
|
categoryId: TaskCategoryID
|
|
|
|
label: string
|
2020-04-21 20:45:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export const UPDATE_TASK_CATEGORY_LABEL = "UPDATE_TASK_CATEGORY_LABEL";
|
|
|
|
|
|
|
|
export function updateTaskCategoryLabel(categoryId: TaskCategoryID, label: string): UpdateTaskCategoryLabel {
|
2020-05-03 18:34:44 +02:00
|
|
|
return { type: UPDATE_TASK_CATEGORY_LABEL, categoryId, label };
|
2020-04-21 20:45:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export function handleUpdateTaskCategoryLabel(project: Project, action: UpdateTaskCategoryLabel): Project {
|
2020-05-03 18:34:44 +02:00
|
|
|
return {
|
|
|
|
...project,
|
|
|
|
params: {
|
|
|
|
...project.params,
|
|
|
|
taskCategories: {
|
|
|
|
...project.params.taskCategories,
|
|
|
|
[action.categoryId]: {
|
|
|
|
...project.params.taskCategories[action.categoryId],
|
|
|
|
label: action.label
|
|
|
|
},
|
|
|
|
}
|
2023-09-01 05:56:07 +02:00
|
|
|
},
|
|
|
|
updatedAt: new Date(),
|
2020-05-03 18:34:44 +02:00
|
|
|
};
|
2020-04-21 20:45:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface UpdateTaskCategoryCost extends Action {
|
2020-05-03 18:34:44 +02:00
|
|
|
categoryId: TaskCategoryID
|
|
|
|
costPerTimeUnit: number
|
2020-04-21 20:45:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export const UPDATE_TASK_CATEGORY_COST = "UPDATE_TASK_CATEGORY_COST";
|
|
|
|
|
|
|
|
export function updateTaskCategoryCost(categoryId: TaskCategoryID, costPerTimeUnit: number): UpdateTaskCategoryCost {
|
2020-05-03 18:34:44 +02:00
|
|
|
return { type: UPDATE_TASK_CATEGORY_COST, categoryId, costPerTimeUnit };
|
2020-04-21 20:45:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export function handleUpdateTaskCategoryCost(project: Project, action: UpdateTaskCategoryCost): Project {
|
2020-05-03 18:34:44 +02:00
|
|
|
return {
|
|
|
|
...project,
|
|
|
|
params: {
|
|
|
|
...project.params,
|
|
|
|
taskCategories: {
|
|
|
|
...project.params.taskCategories,
|
|
|
|
[action.categoryId]: {
|
|
|
|
...project.params.taskCategories[action.categoryId],
|
|
|
|
costPerTimeUnit: action.costPerTimeUnit
|
|
|
|
},
|
|
|
|
}
|
2023-09-01 05:56:07 +02:00
|
|
|
},
|
|
|
|
updatedAt: new Date(),
|
2020-05-03 18:34:44 +02:00
|
|
|
};
|
2020-04-21 20:45:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export const ADD_TASK_CATEGORY = "ADD_TASK_CATEGORY";
|
|
|
|
|
|
|
|
export interface AddTaskCategory extends Action {
|
2020-05-03 18:34:44 +02:00
|
|
|
taskCategory: TaskCategory
|
2020-04-21 20:45:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export function addTaskCategory(taskCategory: TaskCategory): AddTaskCategory {
|
2020-05-03 18:34:44 +02:00
|
|
|
return { type: ADD_TASK_CATEGORY, taskCategory };
|
2020-04-21 20:45:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export function handleAddTaskCategory(project: Project, action: AddTaskCategory): Project {
|
2020-05-03 18:34:44 +02:00
|
|
|
const taskCategory = { ...action.taskCategory };
|
|
|
|
return {
|
|
|
|
...project,
|
|
|
|
params: {
|
|
|
|
...project.params,
|
|
|
|
taskCategories: {
|
|
|
|
...project.params.taskCategories,
|
|
|
|
[taskCategory.id]: taskCategory,
|
|
|
|
}
|
2023-09-01 05:56:07 +02:00
|
|
|
},
|
|
|
|
updatedAt: new Date(),
|
2020-05-03 18:34:44 +02:00
|
|
|
};
|
2020-04-21 20:45:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface RemoveTaskCategory extends Action {
|
2020-05-03 18:34:44 +02:00
|
|
|
taskCategoryId: TaskCategoryID
|
2020-04-21 20:45:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export const REMOVE_TASK_CATEGORY = "REMOVE_TASK_CATEGORY";
|
|
|
|
|
|
|
|
export function removeTaskCategory(taskCategoryId: TaskCategoryID): RemoveTaskCategory {
|
2020-05-03 18:34:44 +02:00
|
|
|
return { type: REMOVE_TASK_CATEGORY, taskCategoryId };
|
2020-04-21 20:45:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export function handleRemoveTaskCategory(project: Project, action: RemoveTaskCategory): Project {
|
2020-05-03 18:34:44 +02:00
|
|
|
const taskCategories = { ...project.params.taskCategories };
|
|
|
|
delete taskCategories[action.taskCategoryId];
|
|
|
|
return {
|
|
|
|
...project,
|
|
|
|
params: {
|
|
|
|
...project.params,
|
|
|
|
taskCategories
|
2023-09-01 05:56:07 +02:00
|
|
|
},
|
|
|
|
updatedAt: new Date(),
|
2020-05-03 18:34:44 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface PatchProject extends Action {
|
|
|
|
from: Project
|
|
|
|
}
|
|
|
|
|
|
|
|
export const PATCH_PROJECT = "PATCH_PROJECT";
|
|
|
|
|
|
|
|
export function patchProject(from: Project): PatchProject {
|
|
|
|
return { type: PATCH_PROJECT, from };
|
|
|
|
}
|
|
|
|
|
|
|
|
export function handlePatchProject(project: Project, action: PatchProject): Project {
|
|
|
|
const p = diff(project, action.from);
|
|
|
|
console.log('patch to apply', p);
|
|
|
|
if (!p) return project;
|
2023-09-01 05:56:07 +02:00
|
|
|
const patched: Project = applyPatch(project, p) as Project
|
|
|
|
if (typeof patched.createdAt === 'string') patched.createdAt = new Date(patched.createdAt)
|
|
|
|
if (typeof patched.updatedAt === 'string') patched.updatedAt = new Date(patched.updatedAt)
|
|
|
|
return patched;
|
2020-04-20 11:14:46 +02:00
|
|
|
}
|