Skip to content

Commit

Permalink
Finish board state (#21)
Browse files Browse the repository at this point in the history
* Finish tool handling

* Merge state to single board state

* Add selectable users
  • Loading branch information
WhiteHoodHacker authored Dec 1, 2023
1 parent fa5fd80 commit 0c37834
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 82 deletions.
10 changes: 7 additions & 3 deletions client/src/@types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
interface Board {
id: number;
owner: User;
title: string;
owner?: User;
arrows: Arrow[];
tasks: Task[];
users: User[];
}
interface Task {
id: number;
Expand All @@ -27,7 +30,8 @@ interface Arrow {
color: string;
}
interface User {
id: number;
name: string;
email: string;
profilePicUrl: string;
email?: string;
profilePicUrl?: string;
}
182 changes: 109 additions & 73 deletions client/src/components/Board/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,70 +35,102 @@ export enum Tool {
};

export default function Board() {
const [board, setBoard] = useState<Board>({
id: 1,
title: "Dream Treehouse Project",
tasks: [
{
id: 1,
title: 'Gather wood',
description: 'Example description!',
width: 200,
height: 100,
posX: 200,
posY: 350,
color: "#f7d9c4"
},
{
id: 2,
title: 'Build door',
width: 200,
height: 100,
posX: 500,
posY: 300,
color: "#faedcb"
},
{
id: 3,
title: 'Build walls',
width: 200,
height: 100,
posX: 500,
posY: 450,
color: "#faedcb"
},
{
id: 4,
title: 'Find cool tree',
width: 200,
height: 100,
posX: 300,
posY: 100,
color: "#f7d9c4"
},
{
id: 5,
title: 'Assemble treehouse',
width: 200,
height: 100,
posX: 800,
posY: 250,
color: "#c9e4de"
},
],
arrows: [
{
id: 1,
from: 1,
to: 2,
color: "#0000ff"
}
],
users: [
{
id: 1,
name: "Alice"
},
{
id: 2,
name: "Bob"
}
]
});
const setTasks = (tasks: Task[]) => {
setBoard({
...board,
tasks
});
};
const setArrows = (arrows: Arrow[]) => {
setBoard({
...board,
arrows
});
};
// const setUsers = (users: User[]) => {
// setBoard({
// ...board,
// users
// });
// };

// Temporary board view state
const [board_view_state, setBoardViewState] = useState<BoardViewState>({
offsetX: 0,
offsetY: 0,
zoom: 1.0,
});

const [tasks, setTaskList] = useState<Task[]>([
{
id: 1,
title: 'Gather wood',
description: 'Example description!',
width: 200,
height: 100,
posX: 200,
posY: 350,
color: "#f7d9c4"
},
{
id: 2,
title: 'Build door',
width: 200,
height: 100,
posX: 500,
posY: 300,
color: "#faedcb"
},
{
id: 3,
title: 'Build walls',
width: 200,
height: 100,
posX: 500,
posY: 450,
color: "#faedcb"
},
{
id: 4,
title: 'Find cool tree',
width: 200,
height: 100,
posX: 300,
posY: 100,
color: "#f7d9c4"
},
{
id: 5,
title: 'Assemble treehouse',
width: 200,
height: 100,
posX: 800,
posY: 250,
color: "#c9e4de"
},
]);

const [arrows, setarrows] = useState<Arrow[]>([
{
id: 1,
from: 1,
to: 2,
color: "#0000ff"
}
]);

// Tool-specific states
const [selectedTool, setSelectedTool] = useState<Tool>(Tool.Pointer);
const [pointerToolState, setPointerToolState] = useState<PointerToolState>({
Expand Down Expand Up @@ -135,7 +167,7 @@ export default function Board() {
const handleTaskClick = (id: number) => {
switch (selectedTool) {
case Tool.Pointer:
const selected_task = tasks.find((t) => t.id == id);
const selected_task = board.tasks.find((t) => t.id == id);
if (selected_task) {
setPointerToolState({
...pointerToolState,
Expand Down Expand Up @@ -167,7 +199,7 @@ export default function Board() {
// TODO: Technically, we should do more calculations to account for a panned canvas
const { clientX, clientY } = e.nativeEvent;
const newTask: Task = {
id: tasks.length + 1, // TODO: Better way of assigning task IDs
id: board.tasks.length + 1, // TODO: Better way of assigning task IDs
title: "Untitled task",
description: "",
width: 200,
Expand All @@ -176,7 +208,7 @@ export default function Board() {
posY: clientY,
color: "#faedcb"
};
setTaskList([...tasks, newTask]);
setTasks([...board.tasks, newTask]);
setSelectedTool(Tool.Pointer);
setPointerToolState({
...pointerToolState,
Expand All @@ -199,30 +231,30 @@ export default function Board() {
};

const updateTask = (task: Task) => {
const taskIdx = tasks.findIndex((t) => t.id == task.id);
const taskIdx = board.tasks.findIndex((t) => t.id == task.id);
if (taskIdx == -1) {
console.error(`Task ${task.id} not found`);
return;
}
console.log(`Updating task ${task.id}`);
const newTasks = tasks.slice();
const newTasks = board.tasks.slice();
newTasks[taskIdx] = task;
setTaskList(newTasks);
setTasks(newTasks);
};

const addArrow = (firstTaskId: number, secondTaskId: number) => {
const newArrow: Arrow = {
id: arrows.length + 1, // TODO: Better way of assigning arrow IDs
id: board.arrows.length + 1, // TODO: Better way of assigning arrow IDs
from: firstTaskId,
to: secondTaskId,
color: arrowToolState.color
};
setarrows([...arrows, newArrow]);
setArrows([...board.arrows, newArrow]);
};

const removeArrow = (firstTaskId: number, secondTaskId: number) => {
const updatedArrows = arrows.filter(arrow => !(arrow.from == firstTaskId && arrow.to == secondTaskId));
setarrows(updatedArrows);
const updatedArrows = board.arrows.filter(arrow => !(arrow.from == firstTaskId && arrow.to == secondTaskId));
setArrows(updatedArrows);
};

return (
Expand All @@ -234,7 +266,7 @@ export default function Board() {
onClick={selectedTool == Tool.Task ? handleAddNewTask : undefined}
>
<Xwrapper>
{tasks.map((task, idx) => {
{board.tasks.map((task, idx) => {
let className = '';
if (pointerToolState._selected_task?.id == task.id) {
className += 'ring ring-offset-2 ring-primary ';
Expand Down Expand Up @@ -263,7 +295,7 @@ export default function Board() {
/>
);
})}
{arrows.map((arrow, idx) => (
{board.arrows.map((arrow, idx) => (
<Xarrow
key={idx}
start={arrow.from.toString()}
Expand All @@ -273,7 +305,10 @@ export default function Board() {
</Xwrapper>
</div>
<div className="z-10 absolute top-4 left-4 right-4 flex flex-col pointer-events-none">
<Navbar />
<Navbar
title={board.title}
handleTitleChange={(title) => setBoard({ ...board, title })}
/>
<div className="relative">
<div className="absolute flex grow-0 top-64">
<Toolbar
Expand All @@ -285,8 +320,9 @@ export default function Board() {
{pointerToolState._selected_task ? (
<TaskDetailsPane
task={pointerToolState._selected_task}
otherTasks={tasks.filter((task) => task.id != pointerToolState._selected_task!.id)}
arrows={arrows}
otherTasks={board.tasks.filter((task) => task.id != pointerToolState._selected_task!.id)}
arrows={board.arrows}
users={board.users}
handleClose={() => setPointerToolState({...pointerToolState, _selected_task: null })}
handleTaskUpdate={updateTask}
addArrow={addArrow}
Expand Down
10 changes: 9 additions & 1 deletion client/src/components/Navbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ import {
} from '@fluentui/react-icons';
import { Tooltip } from 'react-tooltip';

export default function Navbar() {
interface Props {
title: string;
handleTitleChange: (title: string) => void;
};

export default function Navbar(props: Props) {
const { title, handleTitleChange } = props;
return (
<nav className="flex flex-row gap-2 pointer-events-none [&>*]:pointer-events-auto">
<div className="flex panel-surface-050 items-center p-1">
Expand All @@ -22,7 +28,9 @@ export default function Navbar() {
<input
type="text"
className="outline-none bg-transparent h-6 focus:border-b-2 border-surface-150 mx-2 w-full min-w-[10ch] sm:w-[30ch] md:w-[40ch]"
defaultValue={title}
placeholder="Untitled board"
onChange={() => handleTitleChange(title)}
/>
</div>
<div className="flex panel-surface-050 items-center">
Expand Down
11 changes: 6 additions & 5 deletions client/src/components/TaskDetailsPane/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ interface Props {
task: Task;
otherTasks: Task[];
arrows: Arrow[];
users: User[];
handleClose: () => void;
handleTaskUpdate: (task: Task) => void;
addArrow: (firstTaskId: number, secondTaskId: number) => void;
Expand All @@ -33,14 +34,14 @@ export default function TaskDetailsPane(props: Props) {
height: 630
});
const [showDependencyGraph, setShowDependencyGraph] = useState(false);
const personas = [
{value: '1', label: 'Alice'},
{value: '2', label: 'Bob'}
];
const taskOptions = otherTasks.map((t) => ({
value: t.id.toString(),
label: t.title
}));
const userOptions = props.users.map((u) => ({
value: u.id.toString(),
label: u.name
}));

let taskIdsDependingOn: any[] = [];
arrows.map((arrow: Arrow) => {
Expand Down Expand Up @@ -184,7 +185,7 @@ export default function TaskDetailsPane(props: Props) {
<Select
isMulti
name="colors"
options={personas}
options={userOptions}
className="basic-multi-select"
classNamePrefix="select"
/>
Expand Down

0 comments on commit 0c37834

Please sign in to comment.