From 8f2d0ddfc42d4541f9864079e73d7173e6ae8e50 Mon Sep 17 00:00:00 2001 From: Kenan Date: Tue, 20 Feb 2024 13:11:51 +0100 Subject: [PATCH 01/17] removed css from globals.css --- src/app/globals.css | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index 875c01e..b5c61c9 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,33 +1,3 @@ @tailwind base; @tailwind components; @tailwind utilities; - -:root { - --foreground-rgb: 0, 0, 0; - --background-start-rgb: 214, 219, 220; - --background-end-rgb: 255, 255, 255; -} - -@media (prefers-color-scheme: dark) { - :root { - --foreground-rgb: 255, 255, 255; - --background-start-rgb: 0, 0, 0; - --background-end-rgb: 0, 0, 0; - } -} - -body { - color: rgb(var(--foreground-rgb)); - background: linear-gradient( - to bottom, - transparent, - rgb(var(--background-end-rgb)) - ) - rgb(var(--background-start-rgb)); -} - -@layer utilities { - .text-balance { - text-wrap: balance; - } -} From e22b7415fd66ecb2e72de5478a09706c41ab474c Mon Sep 17 00:00:00 2001 From: Kenan Date: Tue, 20 Feb 2024 13:12:51 +0100 Subject: [PATCH 02/17] added background color to body --- src/app/layout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 3314e47..27250f8 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -16,7 +16,7 @@ export default function RootLayout({ }>) { return ( - {children} + {children} ); } From 88483ed07bc3fd9c16e8b3f2fec8d46de0dd12f8 Mon Sep 17 00:00:00 2001 From: Kenan Date: Tue, 20 Feb 2024 15:38:40 +0100 Subject: [PATCH 03/17] added TaskForm component inside task/add page --- src/app/task/add/page.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/task/add/page.tsx b/src/app/task/add/page.tsx index d9a338f..f765c3b 100644 --- a/src/app/task/add/page.tsx +++ b/src/app/task/add/page.tsx @@ -1,3 +1,4 @@ +import TaskForm from "../../components/TaskForm"; export default function AddTask() { - return

AddTask

; + return ; } From 9d254fc2a60fc091977933a5a33c275f79dbb5c7 Mon Sep 17 00:00:00 2001 From: Kenan Date: Tue, 20 Feb 2024 16:04:03 +0100 Subject: [PATCH 04/17] added TaskInput component, which will be for task name, added back icon, to go back to home page --- src/app/components/TaskForm.tsx | 27 +++++++++++++++++++++++++++ src/app/components/TaskInput.tsx | 14 ++++++++++++++ src/app/icons/BackIcon.tsx | 26 ++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 src/app/components/TaskForm.tsx create mode 100644 src/app/components/TaskInput.tsx create mode 100644 src/app/icons/BackIcon.tsx diff --git a/src/app/components/TaskForm.tsx b/src/app/components/TaskForm.tsx new file mode 100644 index 0000000..8413442 --- /dev/null +++ b/src/app/components/TaskForm.tsx @@ -0,0 +1,27 @@ +"use client"; +import Link from "next/link"; +import { BackIcon } from "../icons/BackIcon"; +import TaskInput from "./TaskInput"; +import { useState } from "react"; + +export default function TaskForm({ label }: { label: string }) { + const [value, setValue] = useState(""); + console.log(value); + return ( +
+
+
+ + + + {label} +
+
+ setValue(value)} value={value} /> +
+
+
+ ); +} diff --git a/src/app/components/TaskInput.tsx b/src/app/components/TaskInput.tsx new file mode 100644 index 0000000..daa28b9 --- /dev/null +++ b/src/app/components/TaskInput.tsx @@ -0,0 +1,14 @@ +type TaskInputProps = { + onValueChange: (value: string) => void; + value: string; +}; + +export default function TaskInput({ onValueChange, value }: TaskInputProps) { + return ( + onValueChange(e.target.value)} + className="w-full h-10 p-4 rounded-full border-none focus:outline-none focus:ring-0" + value={value} + /> + ); +} diff --git a/src/app/icons/BackIcon.tsx b/src/app/icons/BackIcon.tsx new file mode 100644 index 0000000..81cad71 --- /dev/null +++ b/src/app/icons/BackIcon.tsx @@ -0,0 +1,26 @@ +export const BackIcon = () => { + return ( + + + + + ); +}; From 547c72d977ba12a6aafa5547126ce2a944b8a1c2 Mon Sep 17 00:00:00 2001 From: bonz88 Date: Fri, 23 Feb 2024 12:04:26 +0100 Subject: [PATCH 05/17] added complexity and priority buttons --- src/app/components/LevelSelector.tsx | 35 ++++++++++++++++++++++++++ src/app/components/TaskForm.tsx | 37 +++++++++++++++++++++++----- src/app/components/TaskInput.tsx | 13 ++++++---- src/app/components/TaskLevels.tsx | 34 +++++++++++++++++++++++++ src/app/icons/BackIcon.tsx | 7 ++++++ src/app/task/add/page.tsx | 2 +- 6 files changed, 116 insertions(+), 12 deletions(-) create mode 100644 src/app/components/LevelSelector.tsx create mode 100644 src/app/components/TaskLevels.tsx diff --git a/src/app/components/LevelSelector.tsx b/src/app/components/LevelSelector.tsx new file mode 100644 index 0000000..c08061e --- /dev/null +++ b/src/app/components/LevelSelector.tsx @@ -0,0 +1,35 @@ +const levels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + +type LevelSelectorProps = { + label: string; + onLevelChange: (level: number) => void; + priority?: number; + complexity?: number; +}; +export default function LevelSelector({ + label, + onLevelChange, + priority, + complexity, +}: LevelSelectorProps) { + return ( +
+ {label} + + {levels.map((level) => ( + + ))} + +
+ ); +} diff --git a/src/app/components/TaskForm.tsx b/src/app/components/TaskForm.tsx index 8413442..8cd5d61 100644 --- a/src/app/components/TaskForm.tsx +++ b/src/app/components/TaskForm.tsx @@ -1,26 +1,51 @@ "use client"; +import { useState } from "react"; import Link from "next/link"; -import { BackIcon } from "../icons/BackIcon"; import TaskInput from "./TaskInput"; -import { useState } from "react"; +import TaskLevels from "./TaskLevels"; +import { BackIcon } from "../icons/BackIcon"; export default function TaskForm({ label }: { label: string }) { const [value, setValue] = useState(""); - console.log(value); + const [priority, setPriority] = useState(0); + const [complexity, setComplexity] = useState(0); + const [taskNameError, setTaskNameError] = useState(""); + + const handlePriority = (level: number) => { + setPriority(level); + }; + + const handleComplexity = (level: number) => { + setComplexity(level); + }; + + console.log("priority: ", priority); + console.log("complexity", complexity); return (
-
-
+
+
- {label} + {label}
setValue(value)} value={value} />
+
+ {taskNameError &&
{taskNameError}
} +
+
+ +
); diff --git a/src/app/components/TaskInput.tsx b/src/app/components/TaskInput.tsx index daa28b9..0fe1b35 100644 --- a/src/app/components/TaskInput.tsx +++ b/src/app/components/TaskInput.tsx @@ -5,10 +5,13 @@ type TaskInputProps = { export default function TaskInput({ onValueChange, value }: TaskInputProps) { return ( - onValueChange(e.target.value)} - className="w-full h-10 p-4 rounded-full border-none focus:outline-none focus:ring-0" - value={value} - /> +
+ Task Name + onValueChange(e.target.value)} + className="w-[398px] h-[60px] p-4 rounded-full border-none focus:outline-none focus:ring-0" + value={value} + /> +
); } diff --git a/src/app/components/TaskLevels.tsx b/src/app/components/TaskLevels.tsx new file mode 100644 index 0000000..f127846 --- /dev/null +++ b/src/app/components/TaskLevels.tsx @@ -0,0 +1,34 @@ +import LevelSelector from "./LevelSelector"; + +type TaskLevelsProps = { + handlePriority: (value: number) => void; + handleComplexity: (value: number) => void; + priority: number; + complexity: number; +}; + +export default function TaskLevels({ + handlePriority, + handleComplexity, + priority, + complexity, +}: TaskLevelsProps) { + return ( +
+
+ handlePriority(level)} + priority={priority} + /> +
+
+ handleComplexity(level)} + complexity={complexity} + /> +
+
+ ); +} diff --git a/src/app/icons/BackIcon.tsx b/src/app/icons/BackIcon.tsx index 81cad71..b1bc964 100644 --- a/src/app/icons/BackIcon.tsx +++ b/src/app/icons/BackIcon.tsx @@ -1,6 +1,11 @@ export const BackIcon = () => { + const iconStyle = { + transform: "scale(0.7)", + transformOrigin: "center center", + }; return ( { xmlns="http://www.w3.org/2000/svg" > { strokeLinejoin="round" /> ; + return ; } From e288d58d76305996755d87a9a6621404a3a5355d Mon Sep 17 00:00:00 2001 From: bonz88 Date: Fri, 23 Feb 2024 12:53:45 +0100 Subject: [PATCH 06/17] added option to select due date and due time --- src/app/components/TaskDueDateTime.tsx | 35 ++++++++++++++++++++++++++ src/app/components/TaskForm.tsx | 21 ++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 src/app/components/TaskDueDateTime.tsx diff --git a/src/app/components/TaskDueDateTime.tsx b/src/app/components/TaskDueDateTime.tsx new file mode 100644 index 0000000..5751b3b --- /dev/null +++ b/src/app/components/TaskDueDateTime.tsx @@ -0,0 +1,35 @@ +type TaskDueDateTimeProps = { + dueDate: string; + dueTime: string; + handleDueDate: (date: string) => void; + handleDueTime: (time: string) => void; +}; +export default function TaskDueDateTime({ + dueTime, + dueDate, + handleDueDate, + handleDueTime, +}: TaskDueDateTimeProps) { + return ( +
+
+ Select Due Date + handleDueDate(e.target.value)} + value={dueDate} + type="date" + /> +
+
+ Select Due Time + handleDueTime(e.target.value)} + value={dueTime} + type="time" + /> +
+
+ ); +} diff --git a/src/app/components/TaskForm.tsx b/src/app/components/TaskForm.tsx index 8cd5d61..ed80aae 100644 --- a/src/app/components/TaskForm.tsx +++ b/src/app/components/TaskForm.tsx @@ -4,11 +4,14 @@ import Link from "next/link"; import TaskInput from "./TaskInput"; import TaskLevels from "./TaskLevels"; import { BackIcon } from "../icons/BackIcon"; +import TaskDueDateTime from "./TaskDueDateTime"; export default function TaskForm({ label }: { label: string }) { const [value, setValue] = useState(""); const [priority, setPriority] = useState(0); const [complexity, setComplexity] = useState(0); + const [dueDate, setDueDate] = useState(""); + const [dueTime, setDueTime] = useState(""); const [taskNameError, setTaskNameError] = useState(""); const handlePriority = (level: number) => { @@ -19,6 +22,16 @@ export default function TaskForm({ label }: { label: string }) { setComplexity(level); }; + const handleDueDate = (date: string) => { + console.log(date); + setDueDate(date); + }; + + const handleDueTime = (time: string) => { + console.log(time); + setDueTime(time); + }; + console.log("priority: ", priority); console.log("complexity", complexity); return ( @@ -46,6 +59,14 @@ export default function TaskForm({ label }: { label: string }) { complexity={complexity} />
+
+ +
); From d0d16b6c5886f6981b5ba64e3723daa91469d152 Mon Sep 17 00:00:00 2001 From: bonz88 Date: Fri, 23 Feb 2024 15:19:20 +0100 Subject: [PATCH 07/17] added input for subtasks --- src/app/components/TaskForm.tsx | 12 +++++++++- src/app/components/TaskInput.tsx | 2 +- src/app/components/TaskSubtasks.tsx | 37 +++++++++++++++++++++++++++++ src/app/icons/BackIcon.tsx | 2 +- src/app/icons/PlusIcon.tsx | 31 ++++++++++++++++++++++++ src/app/types/types.ts | 22 +++++++++++++++++ 6 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 src/app/components/TaskSubtasks.tsx create mode 100644 src/app/icons/PlusIcon.tsx create mode 100644 src/app/types/types.ts diff --git a/src/app/components/TaskForm.tsx b/src/app/components/TaskForm.tsx index ed80aae..dcad613 100644 --- a/src/app/components/TaskForm.tsx +++ b/src/app/components/TaskForm.tsx @@ -5,6 +5,8 @@ import TaskInput from "./TaskInput"; import TaskLevels from "./TaskLevels"; import { BackIcon } from "../icons/BackIcon"; import TaskDueDateTime from "./TaskDueDateTime"; +import { ITask, ISubtask, ITag } from "../types/types"; +import TaskSubtasks from "./TaskSubtasks"; export default function TaskForm({ label }: { label: string }) { const [value, setValue] = useState(""); @@ -12,6 +14,7 @@ export default function TaskForm({ label }: { label: string }) { const [complexity, setComplexity] = useState(0); const [dueDate, setDueDate] = useState(""); const [dueTime, setDueTime] = useState(""); + const [subtasks, setSubtasks] = useState([]); const [taskNameError, setTaskNameError] = useState(""); const handlePriority = (level: number) => { @@ -32,6 +35,10 @@ export default function TaskForm({ label }: { label: string }) { setDueTime(time); }; + const handleSubtasks = (value: string) => { + console.log(value); + }; + console.log("priority: ", priority); console.log("complexity", complexity); return ( @@ -45,7 +52,7 @@ export default function TaskForm({ label }: { label: string }) { {label} -
+
setValue(value)} value={value} />
@@ -67,6 +74,9 @@ export default function TaskForm({ label }: { label: string }) { handleDueTime={handleDueTime} />
+
+ +
); diff --git a/src/app/components/TaskInput.tsx b/src/app/components/TaskInput.tsx index 0fe1b35..be20d44 100644 --- a/src/app/components/TaskInput.tsx +++ b/src/app/components/TaskInput.tsx @@ -9,7 +9,7 @@ export default function TaskInput({ onValueChange, value }: TaskInputProps) { Task Name onValueChange(e.target.value)} - className="w-[398px] h-[60px] p-4 rounded-full border-none focus:outline-none focus:ring-0" + className="w-[398px] h-10 p-4 rounded-full border-none focus:outline-none focus:ring-0" value={value} /> diff --git a/src/app/components/TaskSubtasks.tsx b/src/app/components/TaskSubtasks.tsx new file mode 100644 index 0000000..8aaf937 --- /dev/null +++ b/src/app/components/TaskSubtasks.tsx @@ -0,0 +1,37 @@ +import { useState } from "react"; +import { PlusIcon } from "../icons/PlusIcon"; + +type TaskSubtasksProps = { + handleSubtasks: (value: string) => void; +}; + +export default function TaskSubtasks({ handleSubtasks }: TaskSubtasksProps) { + const [value, setValue] = useState(""); + + const handleSubtaskSubmit = (e: React.FormEvent) => { + e.preventDefault(); + handleSubtasks(value); + setValue(""); + }; + + return ( +
+ Add checklist for subtask: +
+
+ setValue(e.target.value)} + value={value} + /> + +
+
+
+ ); +} diff --git a/src/app/icons/BackIcon.tsx b/src/app/icons/BackIcon.tsx index b1bc964..f8dec6d 100644 --- a/src/app/icons/BackIcon.tsx +++ b/src/app/icons/BackIcon.tsx @@ -5,7 +5,7 @@ export const BackIcon = () => { }; return ( { + return ( + + + + + ); +}; diff --git a/src/app/types/types.ts b/src/app/types/types.ts new file mode 100644 index 0000000..c678f47 --- /dev/null +++ b/src/app/types/types.ts @@ -0,0 +1,22 @@ +export type ITask = { + id: string; + value: string; + isCompleted: boolean; + priority: number; + complexity: number; + dueDate: string; + dueTime: string; + subtasks: ISubtask[]; + tags: ITag[]; +}; + +export type ISubtask = { + id: string; + value: string; + isCompleted: boolean; +}; + +export type ITag = { + id: string; + value: string; +}; From b019b53e0ab03a146c46db8e798bc64da3990f8a Mon Sep 17 00:00:00 2001 From: bonz88 Date: Mon, 26 Feb 2024 12:05:05 +0100 Subject: [PATCH 08/17] deleted tailwind class for width of input --- src/app/components/TaskInput.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/TaskInput.tsx b/src/app/components/TaskInput.tsx index be20d44..fc53a64 100644 --- a/src/app/components/TaskInput.tsx +++ b/src/app/components/TaskInput.tsx @@ -9,7 +9,7 @@ export default function TaskInput({ onValueChange, value }: TaskInputProps) { Task Name onValueChange(e.target.value)} - className="w-[398px] h-10 p-4 rounded-full border-none focus:outline-none focus:ring-0" + className="h-10 p-4 rounded-full border-none focus:outline-none focus:ring-0" value={value} /> From 5b0a994425939ab7f458ebe9da3d912cc93957a0 Mon Sep 17 00:00:00 2001 From: bonz88 Date: Mon, 26 Feb 2024 12:05:57 +0100 Subject: [PATCH 09/17] added option to list substasks --- src/app/components/TaskForm.tsx | 41 ++++++++++++++++++++--- src/app/components/TaskSubtasksList.tsx | 43 +++++++++++++++++++++++++ src/app/icons/DeleteIcon.tsx | 31 ++++++++++++++++++ 3 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 src/app/components/TaskSubtasksList.tsx create mode 100644 src/app/icons/DeleteIcon.tsx diff --git a/src/app/components/TaskForm.tsx b/src/app/components/TaskForm.tsx index dcad613..5f995ec 100644 --- a/src/app/components/TaskForm.tsx +++ b/src/app/components/TaskForm.tsx @@ -7,6 +7,7 @@ import { BackIcon } from "../icons/BackIcon"; import TaskDueDateTime from "./TaskDueDateTime"; import { ITask, ISubtask, ITag } from "../types/types"; import TaskSubtasks from "./TaskSubtasks"; +import TaskSubtasksList from "./TaskSubtasksList"; export default function TaskForm({ label }: { label: string }) { const [value, setValue] = useState(""); @@ -36,14 +37,36 @@ export default function TaskForm({ label }: { label: string }) { }; const handleSubtasks = (value: string) => { - console.log(value); + const subtask: ISubtask = { + id: Math.random().toString(), + value: value, + isCompleted: false, + }; + setSubtasks([...subtasks, subtask]); }; - console.log("priority: ", priority); - console.log("complexity", complexity); + const handleDeleteSubtask = (id: string) => { + const newSubtask = subtasks.filter((subtask) => subtask.id !== id); + setSubtasks(newSubtask); + }; + + const handleEditSubtask = (value: string, id: string) => { + const newSubtask = subtasks.map((subtask) => { + if (subtask.id === id) { + return { + ...subtask, + value, + }; + } + return subtask; + }); + setSubtasks(newSubtask); + }; + + console.log(subtasks); return (
-
+
); diff --git a/src/app/components/TaskSubtasksList.tsx b/src/app/components/TaskSubtasksList.tsx new file mode 100644 index 0000000..c85207c --- /dev/null +++ b/src/app/components/TaskSubtasksList.tsx @@ -0,0 +1,43 @@ +"use client"; +import { useState } from "react"; +import { ISubtask } from "../types/types"; +import { DeleteIcon } from "../icons/DeleteIcon"; + +type TaskSubtasksListProps = { + subtask: ISubtask; + handleDeleteSubtask: (id: string) => void; + handleEditSubtask: (value: string, id: string) => void; +}; + +export default function TaskSubtasksList({ + subtask, + handleDeleteSubtask, + handleEditSubtask, +}: TaskSubtasksListProps) { + const [editedValue, setEditedValue] = useState(subtask.value); + const handleSubmitEdit = ( + e: React.FormEvent, + id: string + ) => { + e.preventDefault(); + handleEditSubtask(editedValue, id); + }; + return ( +
+
handleSubmitEdit(e, subtask.id)}> + setEditedValue(e.target.value)} + value={editedValue} + /> + +
+
+ ); +} diff --git a/src/app/icons/DeleteIcon.tsx b/src/app/icons/DeleteIcon.tsx new file mode 100644 index 0000000..06b44e4 --- /dev/null +++ b/src/app/icons/DeleteIcon.tsx @@ -0,0 +1,31 @@ +type DeleteIconProps = { + className?: string; +}; + +export const DeleteIcon = ({ className }: DeleteIconProps) => { + return ( + + + + + ); +}; From 1d01d3841f529cb45d3570b614d8bd0cdb5b6272 Mon Sep 17 00:00:00 2001 From: bonz88 Date: Mon, 26 Feb 2024 12:11:49 +0100 Subject: [PATCH 10/17] added onBlur on input field --- src/app/components/TaskSubtasksList.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/app/components/TaskSubtasksList.tsx b/src/app/components/TaskSubtasksList.tsx index c85207c..b2ddffb 100644 --- a/src/app/components/TaskSubtasksList.tsx +++ b/src/app/components/TaskSubtasksList.tsx @@ -22,6 +22,10 @@ export default function TaskSubtasksList({ e.preventDefault(); handleEditSubtask(editedValue, id); }; + + const handleBlur = () => { + handleEditSubtask(editedValue, subtask.id); + }; return (
handleSubmitEdit(e, subtask.id)}> @@ -29,6 +33,7 @@ export default function TaskSubtasksList({ className="w-full pl-4 pr-12 py-2 rounded-full focus:outline-none" onChange={(e) => setEditedValue(e.target.value)} value={editedValue} + onBlur={handleBlur} /> +
+
+
+ ); +} + +export default TaskItemAdder; diff --git a/src/app/components/TaskItemList.tsx b/src/app/components/TaskItemList.tsx new file mode 100644 index 0000000..627bba7 --- /dev/null +++ b/src/app/components/TaskItemList.tsx @@ -0,0 +1,41 @@ +import React, { useState } from "react"; +import { IItem } from "../types/types"; +import { DeleteIcon } from "../icons/DeleteIcon"; + +type TaskItemListProps = { + item: T; + onDelete: (id: string) => void; + onEdit: (id: string, value: string) => void; +}; + +function TaskItemList({ + item, + onDelete, + onEdit, +}: TaskItemListProps) { + const [editedValue, setEditedValue] = useState(item.value); + + const handleBlur = () => { + onEdit(item.id, editedValue); + }; + + return ( +
+ setEditedValue(e.target.value)} + value={editedValue} + onBlur={handleBlur} + /> + +
+ ); +} + +export default TaskItemList; diff --git a/src/app/components/TaskTags.tsx b/src/app/components/TaskTags.tsx new file mode 100644 index 0000000..43739e9 --- /dev/null +++ b/src/app/components/TaskTags.tsx @@ -0,0 +1,37 @@ +import { useState } from "react"; +import { PlusIcon } from "../icons/PlusIcon"; + +type TaskTagsProps = { + handleTags: (value: string) => void; +}; + +export default function TaskTags({ handleTags }: TaskTagsProps) { + const [value, setValue] = useState(""); + + const handleTagsSubmit = (e: React.FormEvent) => { + e.preventDefault(); + handleTags(value); + setValue(""); + }; + + return ( +
+ Add Tags +
+
+ setValue(e.target.value)} + value={value} + /> + +
+
+
+ ); +} diff --git a/src/app/components/TaskTagsList.tsx b/src/app/components/TaskTagsList.tsx new file mode 100644 index 0000000..6c26dcb --- /dev/null +++ b/src/app/components/TaskTagsList.tsx @@ -0,0 +1,48 @@ +"use client"; +import { useState } from "react"; +import { ITag } from "../types/types"; +import { DeleteIcon } from "../icons/DeleteIcon"; + +type TaskTagsListProps = { + tag: ITag; + handleDeleteTag: (id: string) => void; + handleEditTag: (value: string, id: string) => void; +}; + +export default function TaskTagsList({ + tag, + handleDeleteTag, + handleEditTag, +}: TaskTagsListProps) { + const [editedValue, setEditedValue] = useState(tag.value); + const handleSubmitEdit = ( + e: React.FormEvent, + id: string + ) => { + e.preventDefault(); + handleEditTag(editedValue, id); + }; + + const handleBlur = () => { + handleEditTag(editedValue, tag.id); + }; + return ( +
+
handleSubmitEdit(e, tag.id)}> + setEditedValue(e.target.value)} + value={editedValue} + onBlur={handleBlur} + /> + +
+
+ ); +} diff --git a/src/app/hooks/useItems.tsx b/src/app/hooks/useItems.tsx new file mode 100644 index 0000000..7c439e1 --- /dev/null +++ b/src/app/hooks/useItems.tsx @@ -0,0 +1,27 @@ +import { useState } from "react"; +import { IItem } from "../types/types"; + +export function useItems() { + const [items, setItems] = useState([]); + + const addItem = (value: string) => { + const newItem: T = { + id: Math.random().toString(), + value, + isCompleted: false, + } as T; + setItems((prevItems) => [...prevItems, newItem]); + }; + + const deleteItem = (id: string) => { + setItems((prevItems) => prevItems.filter((item) => item.id !== id)); + }; + + const editItem = (id: string, value: string) => { + setItems((prevItems) => + prevItems.map((item) => (item.id === id ? { ...item, value } : item)) + ); + }; + + return { items, addItem, deleteItem, editItem }; +} diff --git a/src/app/types/types.ts b/src/app/types/types.ts index c678f47..4567d36 100644 --- a/src/app/types/types.ts +++ b/src/app/types/types.ts @@ -20,3 +20,9 @@ export type ITag = { id: string; value: string; }; + +export type IItem = { + id: string; + value: string; + isCompleted?: boolean; +}; From bace3ee35fa3c4e0d8b4bee281e8930fc25cce85 Mon Sep 17 00:00:00 2001 From: Kenan Date: Wed, 28 Feb 2024 12:47:40 +0100 Subject: [PATCH 12/17] installed redux/toolkit and react-redux --- package-lock.json | 101 +++++++++++++++++++++++++++++++++++++++++++--- package.json | 10 +++-- 2 files changed, 102 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 08957e5..74f3ffb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,11 @@ "name": "task-management-app", "version": "0.1.0", "dependencies": { + "@reduxjs/toolkit": "^2.2.1", "next": "14.1.0", "react": "^18", - "react-dom": "^18" + "react-dom": "^18", + "react-redux": "^9.1.0" }, "devDependencies": { "@types/node": "^20", @@ -432,6 +434,29 @@ "node": ">=14" } }, + "node_modules/@reduxjs/toolkit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.1.tgz", + "integrity": "sha512-8CREoqJovQW/5I4yvvijm/emUiCCmcs4Ev4XPWd4mizSO+dD3g5G6w34QK5AGeNrSH7qM8Fl66j4vuV7dpOdkw==", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.0.1" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, "node_modules/@rushstack/eslint-patch": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.7.2.tgz", @@ -465,13 +490,13 @@ "version": "15.7.11", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", - "dev": true + "devOptional": true }, "node_modules/@types/react": { "version": "18.2.56", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.56.tgz", "integrity": "sha512-NpwHDMkS/EFZF2dONFQHgkPRwhvgq/OAvIaGQzxGSBmaeR++kTg6njr15Vatz0/2VcCEwJQFi6Jf4Q0qBu0rLA==", - "dev": true, + "devOptional": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -491,7 +516,12 @@ "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", - "dev": true + "devOptional": true + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" }, "node_modules/@typescript-eslint/parser": { "version": "6.21.0", @@ -1218,7 +1248,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true + "devOptional": true }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -2416,6 +2446,15 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.3.tgz", + "integrity": "sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -3722,6 +3761,32 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, + "node_modules/react-redux": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.0.tgz", + "integrity": "sha512-6qoDzIO+gbrza8h3hjMA9aq4nwVFCKFtY2iLxCtVT38Swyy2C/dJCGBXHeHLtx6qlg/8qzc2MrhOeduf5K32wQ==", + "dependencies": { + "@types/use-sync-external-store": "^0.0.3", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25", + "react": "^18.0", + "react-native": ">=0.69", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react-native": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -3743,6 +3808,19 @@ "node": ">=8.10.0" } }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz", @@ -3788,6 +3866,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/reselect": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz", + "integrity": "sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg==" + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -4595,6 +4678,14 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 582feb9..6fb02e0 100644 --- a/package.json +++ b/package.json @@ -9,19 +9,21 @@ "lint": "next lint" }, "dependencies": { + "@reduxjs/toolkit": "^2.2.1", + "next": "14.1.0", "react": "^18", "react-dom": "^18", - "next": "14.1.0" + "react-redux": "^9.1.0" }, "devDependencies": { - "typescript": "^5", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", "autoprefixer": "^10.0.1", + "eslint": "^8", + "eslint-config-next": "14.1.0", "postcss": "^8", "tailwindcss": "^3.3.0", - "eslint": "^8", - "eslint-config-next": "14.1.0" + "typescript": "^5" } } From 1c034430288e9ebc3ae0b01feabdbc65053bddd7 Mon Sep 17 00:00:00 2001 From: Kenan Date: Wed, 28 Feb 2024 15:40:08 +0100 Subject: [PATCH 13/17] setup redux --- src/app/components/TaskForm.tsx | 43 +++++++++-- src/app/components/TaskItemAdder.tsx | 2 - src/app/layout.tsx | 5 +- src/app/page.tsx | 111 ++------------------------- src/redux/features/taskSlice.ts | 53 +++++++++++++ src/redux/provider.tsx | 8 ++ src/redux/store.ts | 13 ++++ 7 files changed, 122 insertions(+), 113 deletions(-) create mode 100644 src/redux/features/taskSlice.ts create mode 100644 src/redux/provider.tsx create mode 100644 src/redux/store.ts diff --git a/src/app/components/TaskForm.tsx b/src/app/components/TaskForm.tsx index 5b2df8c..49ee8db 100644 --- a/src/app/components/TaskForm.tsx +++ b/src/app/components/TaskForm.tsx @@ -10,9 +10,12 @@ import TaskSubtasks from "./TaskSubtasks"; import TaskSubtasksList from "./TaskSubtasksList"; import TaskTags from "./TaskTags"; import TaskTagsList from "./TaskTagsList"; -import TaskItemAdder from "./TaskItemAdder"; // Adjust the path as necessary -import TaskItemList from "./TaskItemList"; // Adjust the path as necessary -import { useItems } from "../hooks/useItems"; // Custom hook for managing items +import TaskItemAdder from "./TaskItemAdder"; +import TaskItemList from "./TaskItemList"; +import { useItems } from "../hooks/useItems"; +import { useDispatch } from "react-redux"; +import { AppDispatch } from "../../redux/store"; +import { handleAddTask } from "../../redux/features/taskSlice"; export default function TaskForm({ label }: { label: string }) { const [value, setValue] = useState(""); @@ -36,6 +39,28 @@ export default function TaskForm({ label }: { label: string }) { editItem: editTag, } = useItems(); + const dispatch = useDispatch(); + + const handleTaskSubmit = () => { + console.log("test save task"); + if (!value.trim()) { + setTaskNameError("Task name is required."); + return; + } + setTaskNameError(""); + dispatch( + handleAddTask({ + value, + priority, + complexity, + dueDate, + dueTime, + subtasks, + tags, + }) + ); + }; + const handlePriority = (level: number) => { setPriority(level); }; @@ -107,8 +132,8 @@ export default function TaskForm({ label }: { label: string }) { setTags(newTag); }; */ - console.log("subtasks: ", subtasks); - console.log("tags: ", tags); + //console.log("subtasks: ", subtasks); + //console.log("tags: ", tags); return (
@@ -191,6 +216,14 @@ export default function TaskForm({ label }: { label: string }) { /> ))}
+
+ +
); diff --git a/src/app/components/TaskItemAdder.tsx b/src/app/components/TaskItemAdder.tsx index 0a0d57c..9aaa7f7 100644 --- a/src/app/components/TaskItemAdder.tsx +++ b/src/app/components/TaskItemAdder.tsx @@ -1,5 +1,4 @@ import React, { useState } from "react"; -import { useItems } from "../hooks/useItems"; import { IItem } from "../types/types"; import { PlusIcon } from "../icons/PlusIcon"; @@ -29,7 +28,6 @@ function TaskItemAdder({ className="w-full h-10 rounded-full border-0 outline-none p-4" onChange={(e) => setValue(e.target.value)} value={value} - placeholder={placeholder} /> - - - - ); -} diff --git a/src/app/components/TaskSubtasksList.tsx b/src/app/components/TaskSubtasksList.tsx deleted file mode 100644 index b2ddffb..0000000 --- a/src/app/components/TaskSubtasksList.tsx +++ /dev/null @@ -1,48 +0,0 @@ -"use client"; -import { useState } from "react"; -import { ISubtask } from "../types/types"; -import { DeleteIcon } from "../icons/DeleteIcon"; - -type TaskSubtasksListProps = { - subtask: ISubtask; - handleDeleteSubtask: (id: string) => void; - handleEditSubtask: (value: string, id: string) => void; -}; - -export default function TaskSubtasksList({ - subtask, - handleDeleteSubtask, - handleEditSubtask, -}: TaskSubtasksListProps) { - const [editedValue, setEditedValue] = useState(subtask.value); - const handleSubmitEdit = ( - e: React.FormEvent, - id: string - ) => { - e.preventDefault(); - handleEditSubtask(editedValue, id); - }; - - const handleBlur = () => { - handleEditSubtask(editedValue, subtask.id); - }; - return ( -
-
handleSubmitEdit(e, subtask.id)}> - setEditedValue(e.target.value)} - value={editedValue} - onBlur={handleBlur} - /> - -
-
- ); -} diff --git a/src/app/components/TaskTags.tsx b/src/app/components/TaskTags.tsx deleted file mode 100644 index 43739e9..0000000 --- a/src/app/components/TaskTags.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { useState } from "react"; -import { PlusIcon } from "../icons/PlusIcon"; - -type TaskTagsProps = { - handleTags: (value: string) => void; -}; - -export default function TaskTags({ handleTags }: TaskTagsProps) { - const [value, setValue] = useState(""); - - const handleTagsSubmit = (e: React.FormEvent) => { - e.preventDefault(); - handleTags(value); - setValue(""); - }; - - return ( -
- Add Tags -
-
- setValue(e.target.value)} - value={value} - /> - -
-
-
- ); -} diff --git a/src/app/components/TaskTagsList.tsx b/src/app/components/TaskTagsList.tsx deleted file mode 100644 index 6c26dcb..0000000 --- a/src/app/components/TaskTagsList.tsx +++ /dev/null @@ -1,48 +0,0 @@ -"use client"; -import { useState } from "react"; -import { ITag } from "../types/types"; -import { DeleteIcon } from "../icons/DeleteIcon"; - -type TaskTagsListProps = { - tag: ITag; - handleDeleteTag: (id: string) => void; - handleEditTag: (value: string, id: string) => void; -}; - -export default function TaskTagsList({ - tag, - handleDeleteTag, - handleEditTag, -}: TaskTagsListProps) { - const [editedValue, setEditedValue] = useState(tag.value); - const handleSubmitEdit = ( - e: React.FormEvent, - id: string - ) => { - e.preventDefault(); - handleEditTag(editedValue, id); - }; - - const handleBlur = () => { - handleEditTag(editedValue, tag.id); - }; - return ( -
-
handleSubmitEdit(e, tag.id)}> - setEditedValue(e.target.value)} - value={editedValue} - onBlur={handleBlur} - /> - -
-
- ); -} diff --git a/src/app/page.tsx b/src/app/page.tsx index 3cd194d..3b42e80 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,14 +1,30 @@ "use client"; -import Image from "next/image"; import { useAppSelector } from "../redux/store"; export default function Home() { - const tasks = useAppSelector((state) => state.task); - console.log("tasks: ", tasks); + const tasks = useAppSelector((state) => state.task.tasks); + return (
-

{tasks.value}

+ {tasks.map((task) => ( + <> +

{task.value}

+

{task.priority}

+

{task.complexity}

+

{task.dueDate}

+

{task.dueTime}

+ {task.subtasks.map((subtask) => ( + <> +

{subtask.value}

+

Completed: {subtask.isCompleted}

+ + ))} + {task.tags.map((tag) => ( +

{tag.value}

+ ))} + + ))}
); } diff --git a/src/redux/features/taskSlice.ts b/src/redux/features/taskSlice.ts index fd64284..2c04230 100644 --- a/src/redux/features/taskSlice.ts +++ b/src/redux/features/taskSlice.ts @@ -1,6 +1,7 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { ISubtask, ITag } from "../../app/types/types"; -type InitialState = { + +type ITask = { value: string; priority: number; complexity: number; @@ -10,41 +11,20 @@ type InitialState = { tags: ITag[]; }; +type InitialState = { + tasks: ITask[]; +}; + const initialState = { - value: "", - priority: 0, - complexity: 0, - dueDate: "", - dueTime: "", - subtasks: [], - tags: [], + tasks: [], } as InitialState; -type TaskUpdatePayload = { - value: string; - priority: number; - complexity: number; - dueDate: string; - dueTime: string; - subtasks: ISubtask[]; - tags: ITag[]; -}; - export const taskSlice = createSlice({ name: "task", initialState, reducers: { - handleAddTask: (state, action: PayloadAction) => { - const { value, priority, complexity, dueDate, dueTime, subtasks, tags } = - action.payload; - console.log("Saving task:", action.payload); - state.value = value; - state.priority = priority; - state.complexity = complexity; - state.dueDate = dueDate; - state.dueTime = dueTime; - state.subtasks = subtasks; - state.tags = tags; + handleAddTask: (state, action: PayloadAction) => { + state.tasks = [...state.tasks, action.payload]; }, }, }); From 5f02e15eb5d03aa6feeb6a64524af5d66e4fb8f1 Mon Sep 17 00:00:00 2001 From: Kenan Date: Thu, 29 Feb 2024 13:22:52 +0100 Subject: [PATCH 15/17] added id for every task, added key for every map method in src/app/page.tsx because it failed to deploy on vercel --- src/app/components/TaskForm.tsx | 7 +++++-- src/app/page.tsx | 10 +++++----- src/redux/features/taskSlice.ts | 1 + 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/app/components/TaskForm.tsx b/src/app/components/TaskForm.tsx index d1a26ff..cecc956 100644 --- a/src/app/components/TaskForm.tsx +++ b/src/app/components/TaskForm.tsx @@ -2,6 +2,7 @@ import { useState } from "react"; import { useDispatch } from "react-redux"; import Link from "next/link"; +import { useRouter } from "next/navigation"; import TaskInput from "./TaskInput"; import TaskLevels from "./TaskLevels"; import { BackIcon } from "../icons/BackIcon"; @@ -35,6 +36,8 @@ export default function TaskForm({ label }: { label: string }) { const dispatch = useDispatch(); + const router = useRouter(); + const handleTaskSubmit = () => { if (!value.trim()) { setTaskNameError("Task name is required."); @@ -43,6 +46,7 @@ export default function TaskForm({ label }: { label: string }) { setTaskNameError(""); dispatch( handleAddTask({ + id: Math.random().toString(), value, priority, complexity, @@ -52,6 +56,7 @@ export default function TaskForm({ label }: { label: string }) { tags, }) ); + router.push("/"); }; const handlePriority = (level: number) => { @@ -63,12 +68,10 @@ export default function TaskForm({ label }: { label: string }) { }; const handleDueDate = (date: string) => { - console.log(date); setDueDate(date); }; const handleDueTime = (time: string) => { - console.log(time); setDueTime(time); }; diff --git a/src/app/page.tsx b/src/app/page.tsx index 3b42e80..e80ec51 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -8,22 +8,22 @@ export default function Home() { return (
{tasks.map((task) => ( - <> +

{task.value}

{task.priority}

{task.complexity}

{task.dueDate}

{task.dueTime}

{task.subtasks.map((subtask) => ( - <> +

{subtask.value}

Completed: {subtask.isCompleted}

- +
))} {task.tags.map((tag) => ( -

{tag.value}

+

{tag.value}

))} - +
))}
); diff --git a/src/redux/features/taskSlice.ts b/src/redux/features/taskSlice.ts index 2c04230..055b60c 100644 --- a/src/redux/features/taskSlice.ts +++ b/src/redux/features/taskSlice.ts @@ -2,6 +2,7 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { ISubtask, ITag } from "../../app/types/types"; type ITask = { + id: string; value: string; priority: number; complexity: number; From 78a9a6c7365024c07a1a99e9c374c4f1fd74f4f3 Mon Sep 17 00:00:00 2001 From: Kenan Date: Thu, 29 Feb 2024 13:27:15 +0100 Subject: [PATCH 16/17] changed key --- src/app/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/page.tsx b/src/app/page.tsx index e80ec51..2dc39db 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -8,7 +8,7 @@ export default function Home() { return (
{tasks.map((task) => ( -
+

{task.value}

{task.priority}

{task.complexity}

From e193e79753aa34d76cf291f21e197ca5a7cef525 Mon Sep 17 00:00:00 2001 From: bonz88 Date: Fri, 1 Mar 2024 12:41:26 +0100 Subject: [PATCH 17/17] TaskForm component is now responsive to all screen sizes --- src/app/components/LevelSelector.tsx | 6 ++--- src/app/components/TaskDueDateTime.tsx | 6 ++--- src/app/components/TaskForm.tsx | 32 +++++++++++++++----------- src/app/components/TaskInput.tsx | 4 ++-- src/app/components/TaskItemAdder.tsx | 2 +- src/app/components/TaskItemList.tsx | 2 +- src/app/components/TaskLevels.tsx | 4 ++-- 7 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/app/components/LevelSelector.tsx b/src/app/components/LevelSelector.tsx index c08061e..c6b5808 100644 --- a/src/app/components/LevelSelector.tsx +++ b/src/app/components/LevelSelector.tsx @@ -13,13 +13,13 @@ export default function LevelSelector({ complexity, }: LevelSelectorProps) { return ( -
- {label} +
+ {label} {levels.map((level) => ( - {label} + + {label} +
-
+
setValue(value)} value={value} />
-
- {taskNameError &&
{taskNameError}
} -
-
+ + {taskNameError && ( +
{taskNameError}
+ )} + +
-
+
-
+
{subtasks.map((subtask) => ( -
+
{tags.map((tag) => ( ))}
-
+