import { Project } from "../models/project"; import { Task, TaskID, EstimationConfidence, TaskCategoryID, TaskCategory } from "../models/task"; import { useReducer } from "preact/hooks"; export interface Action { type: string } export type ProjectReducerActions = AddTask | RemoveTask | UpdateTaskEstimation | UpdateProjectLabel | UpdateTaskLabel | UpdateParam | UpdateTaskCategoryLabel | UpdateTaskCategoryCost | AddTaskCategory | RemoveTaskCategory export function useProjectReducer(project: Project) { return useReducer(projectReducer, project); } export function projectReducer(project: Project, action: ProjectReducerActions): Project { 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); } return project; } export interface AddTask extends Action { task: Task } export const ADD_TASK = "ADD_TASK"; export function addTask(task: Task): AddTask { return { type: ADD_TASK, task }; } export function handleAddTask(project: Project, action: AddTask): Project { const task = { ...action.task }; return { ...project, tasks: { ...project.tasks, [task.id]: task, } }; } export interface RemoveTask extends Action { id: TaskID } export const REMOVE_TASK = "REMOVE_TASK"; export function removeTask(id: TaskID): RemoveTask { return { type: REMOVE_TASK, id }; } export function handleRemoveTask(project: Project, action: RemoveTask): Project { const tasks = { ...project.tasks }; delete tasks[action.id]; return { ...project, tasks }; } export interface UpdateTaskEstimation extends Action { id: TaskID confidence: string value: number } export const UPDATE_TASK_ESTIMATION = "UPDATE_TASK_ESTIMATION"; export function updateTaskEstimation(id: TaskID, confidence: EstimationConfidence, value: number): UpdateTaskEstimation { return { type: UPDATE_TASK_ESTIMATION, id, confidence, value }; } export function handleUpdateTaskEstimation(project: Project, action: UpdateTaskEstimation): Project { const estimations = { ...project.tasks[action.id].estimations, [action.confidence]: action.value }; if (estimations.likely < estimations.optimistic) { estimations.likely = estimations.optimistic; } if (estimations.pessimistic < estimations.likely) { estimations.pessimistic = estimations.likely; } return { ...project, tasks: { ...project.tasks, [action.id]: { ...project.tasks[action.id], estimations: estimations, } } }; } export interface UpdateProjectLabel extends Action { label: string } export const UPDATE_PROJECT_LABEL = "UPDATE_PROJECT_LABEL"; export function updateProjectLabel(label: string): UpdateProjectLabel { return { type: UPDATE_PROJECT_LABEL, label }; } export function handleUpdateProjectLabel(project: Project, action: UpdateProjectLabel): Project { return { ...project, label: action.label }; } export interface UpdateTaskLabel extends Action { id: TaskID label: string } export const UPDATE_TASK_LABEL = "UPDATE_TASK_LABEL"; export function updateTaskLabel(id: TaskID, label: string): UpdateTaskLabel { return { type: UPDATE_TASK_LABEL, id, label }; } export function handleUpdateTaskLabel(project: Project, action: UpdateTaskLabel): Project { return { ...project, tasks: { ...project.tasks, [action.id]: { ...project.tasks[action.id], label: action.label, } } }; } export interface UpdateParam extends Action { name: string value: any } export const UPDATE_PARAM = "UPDATE_PARAM"; export function updateParam(name: string, value: any): UpdateParam { return { type: UPDATE_PARAM, name, value }; } export function handleUpdateParam(project: Project, action: UpdateParam): Project { return { ...project, params: { ...project.params, [action.name]: action.value, } }; } export interface UpdateTaskCategoryLabel extends Action { categoryId: TaskCategoryID label: string } export const UPDATE_TASK_CATEGORY_LABEL = "UPDATE_TASK_CATEGORY_LABEL"; export function updateTaskCategoryLabel(categoryId: TaskCategoryID, label: string): UpdateTaskCategoryLabel { return { type: UPDATE_TASK_CATEGORY_LABEL, categoryId, label }; } export function handleUpdateTaskCategoryLabel(project: Project, action: UpdateTaskCategoryLabel): Project { return { ...project, params: { ...project.params, taskCategories: { ...project.params.taskCategories, [action.categoryId]: { ...project.params.taskCategories[action.categoryId], label: action.label }, } } }; } export interface UpdateTaskCategoryCost extends Action { categoryId: TaskCategoryID costPerTimeUnit: number } export const UPDATE_TASK_CATEGORY_COST = "UPDATE_TASK_CATEGORY_COST"; export function updateTaskCategoryCost(categoryId: TaskCategoryID, costPerTimeUnit: number): UpdateTaskCategoryCost { return { type: UPDATE_TASK_CATEGORY_COST, categoryId, costPerTimeUnit }; } export function handleUpdateTaskCategoryCost(project: Project, action: UpdateTaskCategoryCost): Project { return { ...project, params: { ...project.params, taskCategories: { ...project.params.taskCategories, [action.categoryId]: { ...project.params.taskCategories[action.categoryId], costPerTimeUnit: action.costPerTimeUnit }, } } }; } export const ADD_TASK_CATEGORY = "ADD_TASK_CATEGORY"; export interface AddTaskCategory extends Action { taskCategory: TaskCategory } export function addTaskCategory(taskCategory: TaskCategory): AddTaskCategory { return { type: ADD_TASK_CATEGORY, taskCategory }; } export function handleAddTaskCategory(project: Project, action: AddTaskCategory): Project { const taskCategory = { ...action.taskCategory }; return { ...project, params: { ...project.params, taskCategories: { ...project.params.taskCategories, [taskCategory.id]: taskCategory, } } }; } export interface RemoveTaskCategory extends Action { taskCategoryId: TaskCategoryID } export const REMOVE_TASK_CATEGORY = "REMOVE_TASK_CATEGORY"; export function removeTaskCategory(taskCategoryId: TaskCategoryID): RemoveTaskCategory { return { type: REMOVE_TASK_CATEGORY, taskCategoryId }; } export function handleRemoveTaskCategory(project: Project, action: RemoveTaskCategory): Project { const taskCategories = { ...project.params.taskCategories }; delete taskCategories[action.taskCategoryId]; return { ...project, params: { ...project.params, taskCategories } }; }