add create task functionality, refactor, styling

This commit is contained in:
2022-11-20 13:42:48 +01:00
parent e3c77f85f4
commit 9a8c901130
4 changed files with 143 additions and 80 deletions

105
src/components/todolist.tsx Normal file
View File

@@ -0,0 +1,105 @@
import type { ChangeEvent, FC, MouseEventHandler } from "react";
import {
useCreateTaskMutation,
useDeleteTaskMutation,
useDeleteTodolistMutation,
useGetTasksQuery,
usePutTaskMutation,
} from "../services/hooks";
import { memo, useState } from "react";
import { Input } from "./Input";
import { Button } from "./Button";
type Props = {
todolist: any;
};
type Filter = "all" | "active" | "completed";
const Todolist: FC<Props> = ({ todolist }) => {
const { data: tasks, isLoading } = useGetTasksQuery(todolist.id);
const { mutate: putTask } = usePutTaskMutation();
const { mutate: deleteTask } = useDeleteTaskMutation();
const { mutate: deleteTodolist } = useDeleteTodolistMutation();
const { mutateAsync: createTask } = useCreateTaskMutation();
const [newTaskTitle, setNewTaskTitle] = useState("");
const [filter, setFilter] = useState("all");
console.log(newTaskTitle);
const handleChangeStatus = (todolistId: string, task: any) => {
const newTask = { ...task, status: task.status === 0 ? 2 : 0 };
putTask({ todolistId, task: newTask });
};
const handleDeleteTask = (todolistId: string, taskId: string) => {
deleteTask({ todolistId, taskId });
};
const handleDeleteTodolist = (todolistId: string) => {
deleteTodolist(todolistId);
};
const handleAddTask = () => {
createTask({ todolistId: todolist.id, title: newTaskTitle }).then((res) => {
if (res.data.resultCode === 0) setNewTaskTitle("");
});
};
const handleNewTaskTitleChange = (e: ChangeEvent<HTMLInputElement>) => {
setNewTaskTitle(e.target.value);
};
const handleFilterChange: MouseEventHandler<HTMLButtonElement> = (e) => {
setFilter(e.currentTarget.value as Filter);
};
if (isLoading) return <div>loading...</div>;
const filteredTasks = tasks?.data?.items?.filter((task: any) => {
switch (filter) {
case "active":
return task.status === 0;
case "completed":
return task.status === 2;
default:
return true;
}
});
return (
<div
key={todolist.id}
className={
"w- flex w-72 flex-col gap-3 rounded-md border border-gray-300 p-4"
}
>
<div className={"flex items-center justify-between "}>
<h2 className={"text-xl"}>{todolist.title}</h2>
<button onClick={() => handleDeleteTodolist(todolist.id)}>x</button>
</div>
<div className={"flex w-52 gap-4"}>
<Input value={newTaskTitle} onChange={handleNewTaskTitleChange} />
<Button onClick={handleAddTask}>+</Button>
</div>
{filteredTasks.map((task: any) => (
<div className={"flex items-center gap-2"} key={task.id}>
<input
onChange={() => handleChangeStatus(todolist.id, task)}
type={"checkbox"}
checked={[0, 1, 3].includes(task.status)}
/>
<div key={task.id}>{task.title}</div>
<button onClick={() => handleDeleteTask(todolist.id, task.id)}>
X
</button>
</div>
))}
<div className={"flex"}>
<Button onClick={handleFilterChange} value={"all"}>
All
</Button>
<Button onClick={handleFilterChange} value={"active"}>
Active
</Button>
<Button onClick={handleFilterChange} value={"completed"}>
Completed
</Button>
</div>
</div>
);
};
export default memo(Todolist);

View File

@@ -3,58 +3,38 @@ import Head from "next/head";
import { Button } from "../components/Button";
import {
useCreateTodolistMutation,
useDeleteTaskMutation,
useDeleteTodolistMutation,
useGetTasksQuery,
useLogoutMutation,
usePutTaskMutation,
useTodolistsQuery,
} from "../services/hooks";
import { Loader } from "../components/loader";
import { Input } from "../components/Input";
import type { ChangeEvent } from "react";
import { useState } from "react";
import Todolist from "../components/todolist";
const Home: NextPage = () => {
const [newTodolistTitle, setNewTodolistTitle] = useState("");
const { mutate: logout } = useLogoutMutation();
const { data: todolists, isLoading: isTodolistsLoading } =
useTodolistsQuery();
let isLoadingTasks;
const results = useGetTasksQuery(todolists?.map((t) => t.id) || []);
const tasks = results.map((r) => {
if (r.isLoading) isLoadingTasks = true;
return r?.data;
});
const handleLogout = () => {
logout();
};
const { mutate: putTask } = usePutTaskMutation();
const { mutate: deleteTask } = useDeleteTaskMutation();
const { mutateAsync: createTodolist } = useCreateTodolistMutation();
const { mutate: deleteTodolist } = useDeleteTodolistMutation();
const handleChangeStatus = (todolistId: string, task: any) => {
const newTask = { ...task, status: task.status === 0 ? 2 : 0 };
putTask({ todolistId, task: newTask });
};
const handleDeleteTask = (todolistId: string, taskId: string) => {
deleteTask({ todolistId, taskId });
};
const handleAddTodolist = () => {
createTodolist(newTodolistTitle).then((res) => {
if (res.data.resultCode === 0) setNewTodolistTitle("");
});
};
const handleDeleteTodolist = (todolistId: string) => {
deleteTodolist(todolistId);
};
const handleNewTodolistTitleChange = (e: ChangeEvent<HTMLInputElement>) => {
setNewTodolistTitle(e.target.value);
};
if (isTodolistsLoading || isLoadingTasks)
if (isTodolistsLoading)
return (
<div className={"flex h-screen items-center justify-center"}>
<Loader />
@@ -82,39 +62,11 @@ const Home: NextPage = () => {
</label>
<Button onClick={handleAddTodolist}>+</Button>
</div>
{todolists?.map((todolist) => {
const tasksForTodolist = tasks?.find((t) => {
return t?.todolistId === todolist.id;
})?.data.items;
return (
<div
key={todolist.id}
className={"rounded-md border border-gray-300 p-4"}
>
<div className={"flex items-center justify-between "}>
<h2 className={"text-xl"}>{todolist.title}</h2>
<button onClick={() => handleDeleteTodolist(todolist.id)}>
x
</button>
</div>
{tasksForTodolist?.map((task: any) => (
<div className={"flex items-center gap-2"} key={task.id}>
<input
onChange={() => handleChangeStatus(todolist.id, task)}
type={"checkbox"}
checked={[0, 1, 3].includes(task.status)}
/>
<div key={task.id}>{task.title}</div>
<button
onClick={() => handleDeleteTask(todolist.id, task.id)}
>
X
</button>
</div>
))}
</div>
);
})}
<div className={"flex flex-wrap gap-4"}>
{todolists?.map((todolist) => {
return <Todolist todolist={todolist} key={todolist.id} />;
})}
</div>
</main>
</>
);

View File

@@ -1,11 +1,7 @@
import {
useMutation,
useQueries,
useQuery,
useQueryClient,
} from "@tanstack/react-query";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { PostLoginArgs } from "./index";
import {
createTask,
createTodolist,
deleteMe,
deleteTask,
@@ -62,22 +58,16 @@ export const useTodolistsQuery = () => {
});
};
export const useGetTasksQuery = (todolistIds: string[]) => {
const enabled = todolistIds && todolistIds.length > 0;
return useQueries({
queries: todolistIds.map((todolistId) => {
return {
queryKey: ["tasks", todolistId],
queryFn: () =>
getTask(todolistId).then((res) => {
return {
data: res.data,
todolistId,
};
}),
enabled: enabled,
};
}),
export const useGetTasksQuery = (todolistId: string) => {
return useQuery({
queryKey: ["tasks", todolistId],
queryFn: () =>
getTask(todolistId).then((res) => {
return {
data: res.data,
todolistId,
};
}),
});
};
@@ -122,3 +112,15 @@ export const useDeleteTodolistMutation = () => {
},
});
};
export const useCreateTaskMutation = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (args: { todolistId: string; title: string }) =>
createTask(args.todolistId, args.title),
onSuccess: (res) => {
const todolistId = res.data.data.item.todoListId;
queryClient.invalidateQueries(["tasks", todolistId]);
},
});
};

View File

@@ -59,3 +59,7 @@ export const createTodolist = (title: string) => {
export const deleteTodolist = (todolistId: string) => {
return instance.delete(`todo-lists/${todolistId}`);
};
export const createTask = (todolistId: string, title: string) => {
return instance.post(`todo-lists/${todolistId}/tasks`, { title });
};