Skip to content

Commit

Permalink
Merge pull request #1 from sandygudie/new-version
Browse files Browse the repository at this point in the history
New version
  • Loading branch information
sandygudie authored Dec 23, 2023
2 parents c4b4cb3 + 2dfd322 commit b478858
Show file tree
Hide file tree
Showing 30 changed files with 1,147 additions and 610 deletions.
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
as="image"
type="image/svg+xml"
/>
<title>Kanban Task Management App</title>
<title>Kanban</title>
</head>
<body>
<div id="root"></div>
Expand Down
Binary file removed public/Work_7.jpg
Binary file not shown.
Binary file added public/empty-project.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/workspace-placeholder.webp
Binary file not shown.
25 changes: 21 additions & 4 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import React from "react";
import Home from "pages/Home";
import React, { useEffect } from "react";
import Home from "pages/home";

Check failure on line 2 in src/App.tsx

View workflow job for this annotation

GitHub Actions / build

Cannot find module 'pages/home' or its corresponding type declarations.
import { Route, Routes } from "react-router-dom";
import Dashboard from "pages/Dashboard";
import Dashboard from "pages/dashboard";

Check failure on line 4 in src/App.tsx

View workflow job for this annotation

GitHub Actions / build

Cannot find module 'pages/dashboard' or its corresponding type declarations.
import LoadingSpinner from "components/LoadingSpinner";
import NotFound from "pages/NotFound";
import NotFound from "pages/notFound";

Check failure on line 6 in src/App.tsx

View workflow job for this annotation

GitHub Actions / build

Cannot find module 'pages/notFound' or its corresponding type declarations.
import Workspace from "pages/workspace";

function App() {
useEffect(() => {
const currentTheme = localStorage.getItem("theme");
if (currentTheme === null) {
localStorage.setItem("theme", "dark");
}
if (
localStorage.theme === "dark" ||
(!("theme" in localStorage) &&
window.matchMedia("(prefers-color-scheme: dark)").matches)
) {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
}, []);
return (
<React.Suspense
fallback={
Expand All @@ -18,6 +34,7 @@ function App() {
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="*" element={<NotFound />} />
<Route path="/workspace" element={<Workspace />} />
</Routes>
</React.Suspense>
);
Expand Down
271 changes: 271 additions & 0 deletions src/components/Board/ActiveBoard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
import { ChangeEvent, useState } from "react";
import AddBoard from "./AddBoard";
import AddTask from "./AddTask";
import { BsCircleFill } from "react-icons/bs";
import TaskItem from "./TaskItem";
import { Droppable, DragDropContext } from "@hello-pangea/dnd";
import { colorMarker, colorSelection } from "utilis";
import { useDispatch, useSelector } from "react-redux";
import { addTask, appData, deleteTask, editColumnName } from "redux/boardSlice";
import { v4 as uuidv4 } from "uuid";
import { PiDotsThreeLight } from "react-icons/pi";
import Popup from "components/Popup";
import Modal from "components/Modal";
import { AppState, IColumn, ITask } from "types";
import DeleteItem from "components/DeleteItem";
import { AiOutlineDelete } from "react-icons/ai";
import { IoPencil } from "react-icons/io5";
import { FcCheckmark } from "react-icons/fc";
import IconButton from "components/IconButton";
import { IoCloseOutline } from "react-icons/io5";

interface Props {
showSidebar: boolean;
}
export default function ActiveBoard({ showSidebar }: Props) {
const dispatch = useDispatch();
const [isAddTask, setAddTask] = useState(false);
const [isOpenPopup, setOpenPopup] = useState(false);
const [isEditBoard, setEditBoard] = useState(false);
const [isEditColumn, setEditColumn] = useState(false);
const [editedText, setEditedText] = useState("");
const [inputError, setInputError] = useState(false);
const [isDeleteColumn, setDeleteColumn] = useState(false);
const [selectedColumn, setSelectedColumn] = useState<IColumn>();
const data: AppState = useSelector(appData);
const { active } = data;

const onDragEnd = (result: any) => {
if (!result.destination) {
return;
}

const activeCopy = { ...active };
const sourceList = activeCopy.columns.find(
(item: IColumn) => item.name === result.source.droppableId
);

const sourceTask = sourceList?.tasks.find(
(item: ITask, index: number) => index === result.source.index
);
dispatch(deleteTask(sourceTask));
const updatedTasks = {
...sourceTask,
id: uuidv4(),
status: result.destination.droppableId,
};
const position = result.destination.index;
dispatch(addTask({ updatedTasks, position }));
};

const addCard = () => {
setOpenPopup(false);
setAddTask(true);
};

const editColumnHandler = () => {
if (!editedText.length) {
setInputError(true);
} else {
setEditColumn(false);
dispatch(editColumnName({ editedText, selectedColumn }));
}
};

const deleteColumnHandler = () => {
setOpenPopup(false);
setDeleteColumn(true);
};

const editColumnChangeHandler = (e: ChangeEvent<HTMLInputElement>) => {
setInputError(false);
setEditedText(e.target.value);
};

return (
<>
<DragDropContext onDragEnd={onDragEnd}>
<div className="h-[90vh]">
<div
style={{
marginLeft: showSidebar ? "clamp(260px, 10vw, 500px)" : "0px",
}}
className={`z-10 relative h-auto py-4 mb-8 pr-8 pl-8`}
>
<div className="mt-3 z-10 h-full flex gap-x-10 w-full">
{active.columns?.map((item: IColumn, index: number) => {
return (
<div key={item.name} className="w-[250px] shrink-0">
<div className="flex justify-between items-center">
<div
className=" flex gap-x-1 items-center text-gray
font-bold uppercase text-xs tracking-widest"
>
<BsCircleFill
style={{
fill:
index < colorMarker.length
? colorMarker[index]
: colorSelection(),
}}
/>
{isEditColumn && selectedColumn?.id === item.id ? (
<input
type="text"
value={editedText}
onChange={(e) => editColumnChangeHandler(e)}
className={`${
inputError && "border-error"
} border-[1px] w-20 rounded-md py-1 px-2`}
/>
) : (
<span
className={`${
item.name.length > 10
? "truncate w-[10ch]"
: "w-fit"
}`}
>
{" "}
{item.name}
</span>
)}
({item.tasks.length})
</div>
<div className="relative gap-x-2 flex items-center">
{isEditColumn && selectedColumn?.id === item.id ? (
<>
<IconButton
handleClick={() => setEditColumn(false)}
>
<IoCloseOutline className="text-error text-lg font-bold" />
</IconButton>
<IconButton handleClick={editColumnHandler}>
{<FcCheckmark className="text-lg font-bold" />}
</IconButton>
</>

) : (
<IconButton
handleClick={() => {
setEditColumn(true),
setSelectedColumn(item),
setEditedText(item.name);
}}
>
<IoPencil className="text-sm font-bold" />
</IconButton>
)}

<IconButton
handleClick={() => {
setSelectedColumn(item), deleteColumnHandler();
}}
>
{" "}
<AiOutlineDelete className="text-sm text-error" />{" "}
</IconButton>
<IconButton
handleClick={() => {
setOpenPopup(true), setSelectedColumn(item);
}}
>
<div>
<PiDotsThreeLight
className=" relative font-bold"
size={20}
/>
{isOpenPopup && selectedColumn?.id === item.id ? (
<div>
<Popup
handleOpenMenu={() => setOpenPopup(false)}
style={{}}
items={[
{
title: "Add Card",
handler: addCard,
},
]}
/>
</div>
) : null}
</div>
</IconButton>
</div>
</div>

<Droppable droppableId={`${item.name}`}>
{(provided) => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
className="mt-4 h-full"
>
{item.tasks.length > 0 ? (
<div>
{item.tasks.map((tasks: ITask, index: number) => {
const filtered = tasks.subtasks.filter(
(item) => item.isCompleted === true
);
return (
<TaskItem
tasks={tasks}
filtered={filtered}
key={tasks.id}
index={index}
/>
);
})}
</div>
) : (
<div className="w-[250px] shrink-0 h-full">
<div className="h-screen dark:bg-secondary/20 border-dashed border-2 border-gray rounded-lg"></div>
</div>
)}
{provided.placeholder}
</div>
)}
</Droppable>
</div>
);
})}

<div className="mt-8 h-screen w-[280px] pr-8 shrink-0">
<button
onClick={() => setEditBoard(true)}
className="h-full w-full bg-primary/20 cursor-pointer flex items-center flex-col justify-center text-center rounded-lg"
>
<p className="text-xl hover:text-primary/70 text-primary font-bold">
{" "}
+ Add Column
</p>
</button>
</div>
</div>
</div>
</div>
</DragDropContext>

<Modal
open={isAddTask || isEditBoard || isDeleteColumn}
handleClose={() => {
setAddTask(false), setEditBoard(false);
}}
>
{isEditBoard ? (
<AddBoard active={active} handleClose={() => setEditBoard(false)} />
) : isDeleteColumn ? (
<DeleteItem
handleClose={() => setDeleteColumn(false)}
selectedColumn={selectedColumn}
/>
) : (
<AddTask
activeColumn={selectedColumn}
handleClose={() => setAddTask(false)}
/>
)}
</Modal>
</>
);
}
Loading

0 comments on commit b478858

Please sign in to comment.