diff --git a/backend/boards/signals.py b/backend/boards/signals.py index c416de9..2c44daa 100644 --- a/backend/boards/signals.py +++ b/backend/boards/signals.py @@ -8,8 +8,10 @@ from users.models import CustomUser def create_default_board(sender, instance, created, **kwargs): """Signal handler to automatically create a default Board for a user upon creation.""" if created: - board = Board.objects.create(user=instance, name="My Default Board") - - ListBoard.objects.create(board=board, name="Todo", position=1) - ListBoard.objects.create(board=board, name="In Progress", position=2) - ListBoard.objects.create(board=board, name="Done", position=3) \ No newline at end of file + # Create unique board by user id + user_id = instance.id + board = Board.objects.create(user=instance, name=f"Board of #{user_id}") + ListBoard.objects.create(board=board, name="Backlog", position=1) + ListBoard.objects.create(board=board, name="Doing", position=2) + ListBoard.objects.create(board=board, name="Review", position=3) + ListBoard.objects.create(board=board, name="Done", position=4) \ No newline at end of file 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/FlaotingParticles.jsx b/frontend/src/components/FlaotingParticles.jsx index c6d103a..e621f55 100644 --- a/frontend/src/components/FlaotingParticles.jsx +++ b/frontend/src/components/FlaotingParticles.jsx @@ -8,14 +8,7 @@ export function FloatingParticles() { }, []); return ( -
+
- -
+ +
+ {/* Particles Container */} + + {/* Login Box */}
@@ -78,7 +85,8 @@ export function LoginPage() { xmlns="http://www.w3.org/2000/svg" className="stroke-current shrink-0 h-6 w-6" fill="none" - viewBox="0 0 24 24"> + viewBox="0 0 24 24" + >
{/* Login Button */} -
OR
{/* Login with Google Button */} -
-
- -
); diff --git a/frontend/src/components/authentication/SignUpPage.jsx b/frontend/src/components/authentication/SignUpPage.jsx index 08628e8..6fcd086 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(); @@ -55,6 +56,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); @@ -76,9 +79,13 @@ export function SignUp() { return (
- +
- {/* ... (other code) */} +
{/* Register Form */} @@ -136,7 +143,10 @@ export function SignUp() {
OR
{/* Login with Google Button */} - diff --git a/frontend/src/components/kanbanBoard/columnContainer.jsx b/frontend/src/components/kanbanBoard/columnContainer.jsx index 819a980..d6f4565 100644 --- a/frontend/src/components/kanbanBoard/columnContainer.jsx +++ b/frontend/src/components/kanbanBoard/columnContainer.jsx @@ -1,53 +1,16 @@ 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 }) { + // Memoize task IDs to prevent unnecessary recalculations const tasksIds = useMemo(() => { return tasks.map((task) => task.id); }, [tasks]); - const { setNodeRef, attributes, listeners, transform, transition, isDragging } = useSortable({ - id: column.id, - data: { - type: "Column", - column, - }, - disabled: editMode, - }); - - 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 */}
+ {/* Provide a SortableContext for the tasks within the column */} + {/* Render TaskCard for each task in the column */} {tasks.map((task) => ( - + useSortable({ ...props, disabled: false })} + /> ))}
+ {/* Column footer */}
); }; 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. +

diff --git a/frontend/src/components/navigations/IconSideNav.jsx b/frontend/src/components/navigations/IconSideNav.jsx index 02cc1a0..c5d1708 100644 --- a/frontend/src/components/navigations/IconSideNav.jsx +++ b/frontend/src/components/navigations/IconSideNav.jsx @@ -32,12 +32,12 @@ export const SideNav = () => { ); }; -const NavItem = ({ icon, selected, id, setSelected, logo, path }) => { +const NavItem = ({ icon, selected, id, setSelected, path }) => { const navigate = useNavigate(); return ( { setSelected(id); navigate(path);