diff --git a/todoblue/src/app/board/[board]/Types.ts b/todoblue/src/app/board/[board]/Types.ts index 5dd8854..b271c0c 100644 --- a/todoblue/src/app/board/[board]/Types.ts +++ b/todoblue/src/app/board/[board]/Types.ts @@ -28,22 +28,6 @@ export type TaskImportance = "Low" | "Lowest"; -export const IMPORTANCE_TO_NUMBER = { - "Highest": 5, - "High": 4, - "Normal": 3, - "Low": 2, - "Lowest": 1, -} - -export const IMPORTANCE_TO_STRING = { - "Highest": "Critico", - "High": "Importante", - "Normal": "Normale", - "Low": "Opzionale", - "Lowest": "Irrilevante" -} - export type TaskPriority = "Highest" | "High" | @@ -51,22 +35,6 @@ export type TaskPriority = "Low" | "Lowest"; -export const PRIORITY_TO_NUMBER = { - "Highest": 5, - "High": 4, - "Normal": 3, - "Low": 2, - "Lowest": 1, -} - -export const PRIORITY_TO_STRING = { - "Highest": "Urgente", - "High": "Prioritario", - "Normal": "Normale", - "Low": "Rimandabile", - "Lowest": "In qualsiasi momento" -} - export type TaskStatus = "Unfinished" | "InProgress" | diff --git a/todoblue/src/app/board/[board]/doTaskGrouping.tsx b/todoblue/src/app/board/[board]/doTaskGrouping.tsx new file mode 100644 index 0000000..b4cb530 --- /dev/null +++ b/todoblue/src/app/board/[board]/doTaskGrouping.tsx @@ -0,0 +1,180 @@ +import {TaskIconEl} from "@/app/board/[board]/TaskIconEl" +import {TaskIcon, TaskImportance, TaskPriority, TaskStatus, TaskWithId} from "@/app/board/[board]/Types" +import {TaskGroupTitleComponent, TaskGroupComparer, TaskGroup, TaskCategorizer} from "@/app/board/[board]/useBoardTaskArranger" +import {ReactNode} from "react" + + +/** + * **Function** categorizing a {@link TaskWithId} based on its {@link TaskIcon}. + * @param a The task to categorize. + */ +function categorizeTaskByIcon(a: TaskWithId): string {return a.icon} + +/** + * **Function** categorizing a {@link TaskWithId} based on its {@link TaskImportance}. + * @param a The task to categorize. + */ +function categorizeTaskByImportance(a: TaskWithId): string {return a.importance} + +/** + * **Function** categorizing a {@link TaskWithId} based on its {@link TaskPriority}. + * @param a The task to categorize. + */ +function categorizeTaskByPriority(a: TaskWithId): string {return a.priority} + +/** + * **Function** categorizing a {@link TaskWithId} based on its {@link TaskStatus}. + * @param a The task to categorize. + */ +function categorizeTaskByStatus(a: TaskWithId): string {return a.status} + +/** + * **Function** comparing {@link TaskGroup}s by their key. + * @param a The first task group to compare. + * @param b The second task group to compare. + */ +function compareGroupsByKey(a: TaskGroup, b: TaskGroup): number {return a.key.localeCompare(b.key)} + +/** + * **Mapping** from {@link TaskImportance} to a {@link number}. + */ +const IMPORTANCE_TO_NUMBER = { + "Highest": 5, + "High": 4, + "Normal": 3, + "Low": 2, + "Lowest": 1, +} + +/** + * **Mapping** from {@link TaskImportance} to a {@link string} to be displayed as the title of a column. + */ +const IMPORTANCE_TO_STRING = { + "Highest": "Critico", + "High": "Importante", + "Normal": "Normale", + "Low": "Opzionale", + "Lowest": "Irrilevante" +} + +/** + * **Function** comparing {@link TaskGroup}s by their {@link TaskImportance}, with the greatest importance being placed at the start. + * @param a The first task group to compare. + * @param b The second task group to compare. + */ +function compareGroupsByDescendingImportance(a: TaskGroup, b: TaskGroup): number { + const aN = IMPORTANCE_TO_NUMBER[a.key as TaskImportance] + const bN = IMPORTANCE_TO_NUMBER[b.key as TaskImportance] + return bN - aN; +} + +/** + * **Mapping** from {@link TaskPriority} to a {@link number}. + */ +const PRIORITY_TO_NUMBER = { + "Highest": 5, + "High": 4, + "Normal": 3, + "Low": 2, + "Lowest": 1, +} + +/** + * **Mapping** from {@link TaskPriority} to a {@link string} to be displayed as the title of a column. + */ +const PRIORITY_TO_STRING = { + "Highest": "Urgente", + "High": "Prioritario", + "Normal": "Normale", + "Low": "Rimandabile", + "Lowest": "In qualsiasi momento" +} + +/** + * **Function** comparing {@link TaskGroup}s by their {@link TaskPriority}, with the greatest priority being placed at the start. + * @param a The first task group to compare. + * @param b The second task group to compare. + */ +function compareGroupsByDescendingPriority(a: TaskGroup, b: TaskGroup): number { + const aN = PRIORITY_TO_NUMBER[a.key as TaskPriority] + const bN = PRIORITY_TO_NUMBER[b.key as TaskPriority] + return bN - aN; +} + +/** + * **Mapping** from {@link TaskStatus} to a {@link number}. + */ +const STATUS_TO_NUMBER = { + "Unfinished": 1, + "InProgress": 2, + "Complete": 3, +} + +/** + * **Mapping** from {@link TaskStatus} to a {@link string} to be displayed as the title of a column. + */ +const STATUS_TO_STRING = { + "Unfinished": "Da fare", + "InProgress": "In corso", + "Complete": "Completati", +} + +/** + * **Function** comparing {@link TaskGroup}s by their {@link TaskStatus}, with the lowest progress being placed at the start. + * @param a The first task group to compare. + * @param b The second task group to compare. + */ +function compareGroupsByAscendingStatus(a: TaskGroup, b: TaskGroup): number { + const aN = STATUS_TO_NUMBER[a.key as TaskStatus] + const bN = STATUS_TO_NUMBER[b.key as TaskStatus] + return aN - bN; +} + +/** + * **Component** interpreting the key of a {@link TaskGroup} as a {@link TaskIcon} and rendering it followed by its name. + * @param key The key to interpret. + * @constructor + * @todo Check accessibility status. + */ +function TaskGroupTitleFromIcon({key}: {key: string}): ReactNode { + let icon = key as TaskIcon; + return <> + +   + {key} + +} + +/** + * **Component** interpreting the key of a {@link TaskGroup} as {@link TaskImportance} and rendering its name according to {@link IMPORTANCE_TO_STRING}. + * @param key The key to interpret. + * @constructor + */ +function TaskGroupTitleFromImportance({key}: {key: string}): ReactNode { + return IMPORTANCE_TO_STRING[key as TaskImportance]; +} + +/** + * **Component** interpreting the key of a {@link TaskGroup} as {@link TaskPriority} and rendering its name according to {@link PRIORITY_TO_STRING}. + * @param key The key to interpret. + * @constructor + */ +function TaskGroupTitleFromPriority({key}: {key: string}): ReactNode { + return PRIORITY_TO_STRING[key as TaskPriority]; +} + +/** + * **Component** interpreting the key of a {@link TaskGroup} as {@link TaskStatus} and rendering its name according to {@link STATUS_TO_STRING}. + * @param key The key to interpret. + * @constructor + */ +function TaskGroupTitleFromStatus({key}: {key: string}): ReactNode { + return STATUS_TO_STRING[key as TaskStatus]; +} + +export const TASK_GROUPERS: [TaskCategorizer, TaskGroupComparer, TaskGroupTitleComponent][] = [ + [categorizeTaskByIcon, compareGroupsByKey, TaskGroupTitleFromIcon], + [categorizeTaskByStatus, compareGroupsByAscendingStatus, TaskGroupTitleFromStatus], + [categorizeTaskByImportance, compareGroupsByDescendingImportance, TaskGroupTitleFromImportance], + [categorizeTaskByPriority, compareGroupsByDescendingPriority, TaskGroupTitleFromPriority], +] diff --git a/todoblue/src/app/board/[board]/doTaskSorting.tsx b/todoblue/src/app/board/[board]/doTaskSorting.tsx new file mode 100644 index 0000000..5a680be --- /dev/null +++ b/todoblue/src/app/board/[board]/doTaskSorting.tsx @@ -0,0 +1,14 @@ +import {TaskWithId} from "@/app/board/[board]/Types" +import {TaskSortingFunction} from "@/app/board/[board]/useBoardTaskArranger" + + +/** + * **Function** comparing {@link Task}s by their text, following the order proposed by {@link string.localeCompare}. + * @param a The first task to compare. + * @param b The second task to compare. + */ +function compareTasksByText(a: TaskWithId, b: TaskWithId) {return a.text.localeCompare(b.text)} + +export const TASK_SORTERS: TaskSortingFunction[] = [ + compareTasksByText, +]; diff --git a/todoblue/src/app/board/[board]/useBoard.tsx b/todoblue/src/app/board/[board]/useBoard.tsx index 0cd4168..daf3823 100644 --- a/todoblue/src/app/board/[board]/useBoard.tsx +++ b/todoblue/src/app/board/[board]/useBoard.tsx @@ -1,57 +1,14 @@ "use client"; -import {TaskIconEl} from "@/app/board/[board]/TaskIconEl" -import {BoardAction, IMPORTANCE_TO_NUMBER, IMPORTANCE_TO_STRING, PRIORITY_TO_NUMBER, PRIORITY_TO_STRING, TaskImportance, TaskPriority} from "@/app/board/[board]/Types" -import {TaskIcon, TaskWithId} from "@/app/board/[board]/Types" +import {TASK_GROUPERS} from "@/app/board/[board]/doTaskGrouping" +import {TASK_SORTERS} from "@/app/board/[board]/doTaskSorting" +import {BoardAction} from "@/app/board/[board]/Types" import {useBoardWebSocket} from "@/app/board/[board]/useBoardWebSocket" -import {GroupNamingFunction, GroupSortingFunction, TaskGroup, TaskGroupingFunction, TaskSortingFunction, useBoardTaskArranger} from "@/app/board/[board]/useBoardTaskArranger" +import {TaskGroup, useBoardTaskArranger} from "@/app/board/[board]/useBoardTaskArranger" import {useBoardTitleEditor} from "@/app/board/[board]/useBoardTitleEditor" import {useCycleState} from "@/app/useCycleState" import {Dispatch, SetStateAction} from "react" -function groupTasksByIcon(a: TaskWithId) {return a.icon} -function groupTasksByImportance(a: TaskWithId) {return a.importance} -function groupTasksByPriority(a: TaskWithId) {return a.priority} - -function sortGroupsByKey(a: TaskGroup, b: TaskGroup) {return a.key.localeCompare(b.key)} -function sortGroupsByImportance(a: TaskGroup, b: TaskGroup) { - const aN = IMPORTANCE_TO_NUMBER[a.key as TaskImportance] - const bN = IMPORTANCE_TO_NUMBER[b.key as TaskImportance] - return bN - aN; -} -function sortGroupsByPriority(a: TaskGroup, b: TaskGroup) { - const aN = PRIORITY_TO_NUMBER[a.key as TaskPriority] - const bN = PRIORITY_TO_NUMBER[b.key as TaskPriority] - return bN - aN; -} - -function iconToTitle(a: string) { - let icon = a as TaskIcon; - return <> - -   - {a} - -} -function importanceToTitle(a: string) { - return IMPORTANCE_TO_STRING[a as TaskImportance]; -} -function priorityToTitle(a: string) { - return PRIORITY_TO_STRING[a as TaskPriority]; -} - -const TASK_GROUPERS: [TaskGroupingFunction, GroupSortingFunction, GroupNamingFunction][] = [ - [groupTasksByIcon, sortGroupsByKey, iconToTitle], - [groupTasksByImportance, sortGroupsByImportance, importanceToTitle], - [groupTasksByPriority, sortGroupsByPriority, priorityToTitle], -] - -function sortTasksByText(a: TaskWithId, b: TaskWithId) {return a.text.localeCompare(b.text)} - -const TASK_SORTERS: TaskSortingFunction[] = [ - sortTasksByText, -]; - export interface UseBoardReturns { title: string, taskGroups: TaskGroup[], diff --git a/todoblue/src/app/board/[board]/useBoardTaskArranger.ts b/todoblue/src/app/board/[board]/useBoardTaskArranger.ts index 07b04b8..bccd846 100644 --- a/todoblue/src/app/board/[board]/useBoardTaskArranger.ts +++ b/todoblue/src/app/board/[board]/useBoardTaskArranger.ts @@ -9,12 +9,12 @@ export type TaskGroup = { tasks: TaskWithId[], } -export type TaskGroupingFunction = (a: TaskWithId) => string -export type GroupSortingFunction = (a: TaskGroup, b: TaskGroup) => number; -export type GroupNamingFunction = (a: string) => ReactNode; +export type TaskCategorizer = (a: TaskWithId) => string +export type TaskGroupComparer = (a: TaskGroup, b: TaskGroup) => number; +export type TaskGroupTitleComponent = (a: {key: string}) => ReactNode; export type TaskSortingFunction = (a: TaskWithId, b: TaskWithId) => number; -export function arrangeBoardTasks(tasksById: { [p: string]: Task }, taskGrouper: TaskGroupingFunction, groupSorter: GroupSortingFunction, groupNamer: GroupNamingFunction, taskSorter: TaskSortingFunction): TaskGroup[] { +export function arrangeBoardTasks(tasksById: { [p: string]: Task }, taskGrouper: TaskCategorizer, groupSorter: TaskGroupComparer, groupNamer: TaskGroupTitleComponent, taskSorter: TaskSortingFunction): TaskGroup[] { const groupsByKey: {[group: string]: TaskWithId[]} = {} for(const [id, task] of Object.entries(tasksById)) { @@ -33,7 +33,7 @@ export function arrangeBoardTasks(tasksById: { [p: string]: Task }, taskGrouper: const groups: TaskGroup[] = [] for(const [key, tasks] of Object.entries(groupsByKey)) { - const name = groupNamer(key); + const name = groupNamer({key}); groups.push({key, name, tasks}) } @@ -43,7 +43,7 @@ export function arrangeBoardTasks(tasksById: { [p: string]: Task }, taskGrouper: } -export function useBoardTaskArranger(tasksById: { [p: string]: Task }, taskGrouper: TaskGroupingFunction, groupSorter: GroupSortingFunction, groupNamer: GroupNamingFunction, taskSorter: TaskSortingFunction) { +export function useBoardTaskArranger(tasksById: { [p: string]: Task }, taskGrouper: TaskCategorizer, groupSorter: TaskGroupComparer, groupNamer: TaskGroupTitleComponent, taskSorter: TaskSortingFunction) { const taskGroups = useMemo(() => arrangeBoardTasks(tasksById, taskGrouper, groupSorter, groupNamer, taskSorter), [tasksById, taskGrouper, taskSorter, groupSorter]) return {taskGroups}; diff --git a/todoblue/src/app/board/[board]/useBoardTitleEditor.ts b/todoblue/src/app/board/[board]/useBoardTitleEditor.ts index 38124c6..d88af92 100644 --- a/todoblue/src/app/board/[board]/useBoardTitleEditor.ts +++ b/todoblue/src/app/board/[board]/useBoardTitleEditor.ts @@ -1,6 +1,6 @@ "use client"; -import {BoardAction} from "@/app/board/[board]/types" +import {BoardAction} from "@/app/board/[board]/Types" import {useCallback, useState} from "react" diff --git a/todoblue/src/app/board/[board]/useBoardWebSocket.ts b/todoblue/src/app/board/[board]/useBoardWebSocket.ts index 1bdcfcf..39d3bee 100644 --- a/todoblue/src/app/board/[board]/useBoardWebSocket.ts +++ b/todoblue/src/app/board/[board]/useBoardWebSocket.ts @@ -1,6 +1,6 @@ 'use client'; -import {BoardAction} from "@/app/board/[board]/types" +import {BoardAction} from "@/app/board/[board]/Types" import {useBoardState} from "@/app/board/[board]/useBoardState" import {useBoardWebSocketURL} from "@/app/board/[board]/useBoardWebSocketURL" import {useCallback} from "react"