From 5051f1f460f5d64c81f88722763a9c32f1c44860 Mon Sep 17 00:00:00 2001 From: sosokker Date: Thu, 23 Nov 2023 12:39:09 +0700 Subject: [PATCH 1/6] Make Column undruggable --- .../kanbanBoard/columnContainer.jsx | 93 +++++-------------- .../kanbanBoard/columnContainerWrapper.jsx | 6 +- .../components/kanbanBoard/kanbanBoard.jsx | 92 +++++------------- .../components/navigations/IconSideNav.jsx | 4 +- 4 files changed, 47 insertions(+), 148 deletions(-) diff --git a/frontend/src/components/kanbanBoard/columnContainer.jsx b/frontend/src/components/kanbanBoard/columnContainer.jsx index 819a980..5b9648e 100644 --- a/frontend/src/components/kanbanBoard/columnContainer.jsx +++ b/frontend/src/components/kanbanBoard/columnContainer.jsx @@ -1,53 +1,31 @@ import { SortableContext, useSortable } from "@dnd-kit/sortable"; -import { BsFillTrashFill } from "react-icons/bs"; import { AiOutlinePlusCircle } from "react-icons/ai"; -import { CSS } from "@dnd-kit/utilities"; -import { useMemo, useState } from "react"; +import { useMemo } from "react"; import { TaskCard } from "./taskCard"; -export function ColumnContainer({ column, deleteColumn, updateColumn, createTask, tasks, deleteTask, updateTask }) { - const [editMode, setEditMode] = useState(false); - +export function ColumnContainer({ column, createTask, tasks, deleteTask, updateTask }) { const tasksIds = useMemo(() => { return tasks.map((task) => task.id); }, [tasks]); - const { setNodeRef, attributes, listeners, transform, transition, isDragging } = useSortable({ + const { + setNodeRef: columnNodeRef, + attributes: columnAttributes, + listeners: columnListeners, + } = useSortable({ id: column.id, data: { type: "Column", column, }, - disabled: editMode, + disabled: true, // Disable drag for the entire column }); - const style = { - transition, - transform: CSS.Transform.toString(transform), - }; - - if (isDragging) { - return ( -
- ); - } - return (
{/* Column title */}
{ - setEditMode(true); - }} className=" ml-3 text-md - cursor-grab font-bold flex items-center justify-between "> -
- {!editMode && column.title} - {editMode && ( - updateColumn(column.id, e.target.value)} - autoFocus - onBlur={() => { - setEditMode(false); - }} - onKeyDown={(e) => { - if (e.key !== "Enter") return; - setEditMode(false); - }} - /> - )} -
- +
{column.title}
{/* Column task container */}
{tasks.map((task) => ( - + useSortable({ ...props, disabled: false })} + /> ))}
+ {/* Column footer */}
OR
{/* Login with Google Button */} -
-
- -
); diff --git a/frontend/src/components/authentication/SignUpPage.jsx b/frontend/src/components/authentication/SignUpPage.jsx index 08628e8..0492412 100644 --- a/frontend/src/components/authentication/SignUpPage.jsx +++ b/frontend/src/components/authentication/SignUpPage.jsx @@ -5,6 +5,7 @@ import { useGoogleLogin } from "@react-oauth/google"; import { NavPreLogin } from "../navigations/NavPreLogin"; import { useAuth } from "src/hooks/AuthHooks"; import { createUser, googleLogin } from "src/api/AuthenticationApi"; +import { FloatingParticles } from "../FlaotingParticles"; export function SignUp() { const Navigate = useNavigate(); @@ -76,9 +77,13 @@ export function SignUp() { return (
- +
- {/* ... (other code) */} +
{/* Register Form */} @@ -136,7 +141,10 @@ export function SignUp() {
OR
{/* Login with Google Button */} - diff --git a/frontend/src/components/landingPage/LandingPage.jsx b/frontend/src/components/landingPage/LandingPage.jsx index e26a44a..1b0bd9e 100644 --- a/frontend/src/components/landingPage/LandingPage.jsx +++ b/frontend/src/components/landingPage/LandingPage.jsx @@ -2,13 +2,10 @@ import { FloatingParticles } from "../FlaotingParticles"; export function LandingPage() { return ( -
+
{/* Particles Container */} {/* Navbar */} -
-
-
@@ -24,12 +21,18 @@ export function LandingPage() { -

Unleash productivity with our personal task and project management.

+

+ Unleash productivity with our personal task and project + management. +

From e83e58db0740e9c18af52c2bde982c1fa31f22df Mon Sep 17 00:00:00 2001 From: sosokker Date: Thu, 23 Nov 2023 16:12:50 +0700 Subject: [PATCH 6/6] Make Kanban More responsive, auto add task for new user --- backend/tasks/signals.py | 66 ++++++++++++++++--- .../components/authentication/SignUpPage.jsx | 2 + .../components/kanbanBoard/kanbanBoard.jsx | 20 ++---- 3 files changed, 65 insertions(+), 23 deletions(-) diff --git a/backend/tasks/signals.py b/backend/tasks/signals.py index 063292e..4c9e6f2 100644 --- a/backend/tasks/signals.py +++ b/backend/tasks/signals.py @@ -27,15 +27,63 @@ def update_priority(sender, instance, **kwargs): instance.priority = Todo.EisenhowerMatrix.NOT_IMPORTANT_NOT_URGENT -@receiver(post_save, sender=Todo) -def assign_todo_to_listboard(sender, instance, created, **kwargs): - """Signal handler to automatically assign a Todo to the first ListBoard in the user's Board upon creation.""" +# @receiver(post_save, sender=Todo) +# def assign_todo_to_listboard(sender, instance, created, **kwargs): +# """Signal handler to automatically assign a Todo to the first ListBoard in the user's Board upon creation.""" +# if created: +# user_board = instance.user.board_set.first() + +# if user_board: +# first_list_board = user_board.listboard_set.order_by('position').first() + +# if first_list_board: +# instance.list_board = first_list_board +# instance.save() + + +@receiver(post_save, sender=ListBoard) +def create_placeholder_tasks(sender, instance, created, **kwargs): + """ + Signal handler to create placeholder tasks for each ListBoard. + """ if created: - user_board = instance.user.board_set.first() + list_board_position = instance.position - if user_board: - first_list_board = user_board.listboard_set.order_by('position').first() + if list_board_position == 1: + placeholder_tasks = [ + {"title": "Normal Task Example"}, + {"title": "Task with Extra Information Example", "description": "Description for Task 2"}, + ] + elif list_board_position == 2: + placeholder_tasks = [ + {"title": "Time Task Example #1", "description": "Description for Task 2", + "start_event": timezone.now(), "end_event": timezone.now() + timezone.timedelta(days=5)}, + ] + elif list_board_position == 3: + placeholder_tasks = [ + {"title": "Time Task Example #2", "description": "Description for Task 2", + "start_event": timezone.now(), "end_event": timezone.now() + timezone.timedelta(days=30)}, + ] + elif list_board_position == 4: + placeholder_tasks = [ + {"title": "Completed Task Example", "description": "Description for Task 2", + "start_event": timezone.now(), "completed": True}, + ] + else: + placeholder_tasks = [ + {"title": "Default Task Example"}, + ] - if first_list_board: - instance.list_board = first_list_board - instance.save() \ No newline at end of file + for task_data in placeholder_tasks: + Todo.objects.create( + list_board=instance, + user=instance.board.user, + title=task_data["title"], + notes=task_data.get("description", ""), + is_active=True, + start_event=task_data.get("start_event"), + end_event=task_data.get("end_event"), + completed=task_data.get("completed", False), + creation_date=timezone.now(), + last_update=timezone.now(), + ) \ No newline at end of file diff --git a/frontend/src/components/authentication/SignUpPage.jsx b/frontend/src/components/authentication/SignUpPage.jsx index 08628e8..b0fdc60 100644 --- a/frontend/src/components/authentication/SignUpPage.jsx +++ b/frontend/src/components/authentication/SignUpPage.jsx @@ -55,6 +55,8 @@ export function SignUp() { const googleLoginImplicit = useGoogleLogin({ flow: "auth-code", redirect_uri: "postmessage", + scope: + "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/calendar.acls.readonly https://www.googleapis.com/auth/calendar.events.readonly", onSuccess: async (response) => { try { const loginResponse = await googleLogin(response.code); diff --git a/frontend/src/components/kanbanBoard/kanbanBoard.jsx b/frontend/src/components/kanbanBoard/kanbanBoard.jsx index 2e79835..b79cf50 100644 --- a/frontend/src/components/kanbanBoard/kanbanBoard.jsx +++ b/frontend/src/components/kanbanBoard/kanbanBoard.jsx @@ -7,7 +7,6 @@ import { TaskCard } from "./taskCard"; import { axiosInstance } from "src/api/AxiosConfig"; export function KanbanBoard() { - const [refreshKey, setRefreshKey] = useState(0); const [columns, setColumns] = useState([]); const [boardId, setBoardData] = useState(); const [isLoading, setLoading] = useState(false); @@ -17,10 +16,6 @@ export function KanbanBoard() { // ---------------- END STATE INITIATE ---------------- - const refreshSortableContext = () => { - setRefreshKey((prevKey) => prevKey + 1); - }; - const sensors = useSensors( useSensor(PointerSensor, { activationConstraint: { @@ -42,7 +37,7 @@ export function KanbanBoard() { const createTask = async (columnId) => { try { const response = await axiosInstance.post("todo/", { - title: `Task ${tasks.length + 1}`, + title: `New Task`, importance: 1, difficulty: 1, challenge: false, @@ -53,7 +48,6 @@ export function KanbanBoard() { priority: 1, list_board: columnId, }); - const newTask = { id: response.data.id, columnId, @@ -61,13 +55,12 @@ export function KanbanBoard() { }; setTasks((prevTasks) => [...prevTasks, newTask]); - refreshSortableContext(); } catch (error) { handleApiError(error, "creating task"); } }; - const deleteTask = async (id, tasks) => { + const deleteTask = async (id) => { try { await axiosInstance.delete(`todo/${id}/`); const newTasks = tasks.filter((task) => task.id !== id); @@ -80,7 +73,7 @@ export function KanbanBoard() { const updateTask = async (id, content, tasks) => { try { if (content === "") { - await deleteTask(id, tasks, setTasks); + await deleteTask(id); } else { const response = await axiosInstance.put(`todo/${id}/`, { content }); @@ -188,7 +181,7 @@ export function KanbanBoard() { createTask={createTask} deleteTask={deleteTask} updateTask={updateTask} - tasks={tasks.filter((task) => task.columnId === col.id)} + tasks={(tasks || []).filter((task) => task.columnId === col.id)} /> ))}{" "} @@ -201,7 +194,7 @@ export function KanbanBoard() { {createPortal( {/* Render the active task as a draggable overlay */} - {activeTask && } + , document.body )} @@ -297,9 +290,8 @@ export function KanbanBoard() { } const isOverAColumn = over.data.current?.type === "Column"; - // Move the Task to a different column and update columnId - if (isActiveATask && isOverAColumn) { + if (isActiveATask && isOverAColumn && tasks.some((task) => task.columnId !== overId)) { setTasks((tasks) => { const activeIndex = tasks.findIndex((t) => t.id === activeId);