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 { Button } from "../components/Button";
import { import {
useCreateTodolistMutation, useCreateTodolistMutation,
useDeleteTaskMutation,
useDeleteTodolistMutation,
useGetTasksQuery,
useLogoutMutation, useLogoutMutation,
usePutTaskMutation,
useTodolistsQuery, useTodolistsQuery,
} from "../services/hooks"; } from "../services/hooks";
import { Loader } from "../components/loader"; import { Loader } from "../components/loader";
import { Input } from "../components/Input"; import { Input } from "../components/Input";
import type { ChangeEvent } from "react"; import type { ChangeEvent } from "react";
import { useState } from "react"; import { useState } from "react";
import Todolist from "../components/todolist";
const Home: NextPage = () => { const Home: NextPage = () => {
const [newTodolistTitle, setNewTodolistTitle] = useState(""); const [newTodolistTitle, setNewTodolistTitle] = useState("");
const { mutate: logout } = useLogoutMutation(); const { mutate: logout } = useLogoutMutation();
const { data: todolists, isLoading: isTodolistsLoading } = const { data: todolists, isLoading: isTodolistsLoading } =
useTodolistsQuery(); 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 = () => { const handleLogout = () => {
logout(); logout();
}; };
const { mutate: putTask } = usePutTaskMutation();
const { mutate: deleteTask } = useDeleteTaskMutation();
const { mutateAsync: createTodolist } = useCreateTodolistMutation(); 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 = () => { const handleAddTodolist = () => {
createTodolist(newTodolistTitle).then((res) => { createTodolist(newTodolistTitle).then((res) => {
if (res.data.resultCode === 0) setNewTodolistTitle(""); if (res.data.resultCode === 0) setNewTodolistTitle("");
}); });
}; };
const handleDeleteTodolist = (todolistId: string) => {
deleteTodolist(todolistId);
};
const handleNewTodolistTitleChange = (e: ChangeEvent<HTMLInputElement>) => { const handleNewTodolistTitleChange = (e: ChangeEvent<HTMLInputElement>) => {
setNewTodolistTitle(e.target.value); setNewTodolistTitle(e.target.value);
}; };
if (isTodolistsLoading || isLoadingTasks) if (isTodolistsLoading)
return ( return (
<div className={"flex h-screen items-center justify-center"}> <div className={"flex h-screen items-center justify-center"}>
<Loader /> <Loader />
@@ -82,39 +62,11 @@ const Home: NextPage = () => {
</label> </label>
<Button onClick={handleAddTodolist}>+</Button> <Button onClick={handleAddTodolist}>+</Button>
</div> </div>
{todolists?.map((todolist) => { <div className={"flex flex-wrap gap-4"}>
const tasksForTodolist = tasks?.find((t) => { {todolists?.map((todolist) => {
return t?.todolistId === todolist.id; return <Todolist todolist={todolist} key={todolist.id} />;
})?.data.items; })}
return ( </div>
<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>
);
})}
</main> </main>
</> </>
); );

View File

@@ -1,11 +1,7 @@
import { import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
useMutation,
useQueries,
useQuery,
useQueryClient,
} from "@tanstack/react-query";
import type { PostLoginArgs } from "./index"; import type { PostLoginArgs } from "./index";
import { import {
createTask,
createTodolist, createTodolist,
deleteMe, deleteMe,
deleteTask, deleteTask,
@@ -62,22 +58,16 @@ export const useTodolistsQuery = () => {
}); });
}; };
export const useGetTasksQuery = (todolistIds: string[]) => { export const useGetTasksQuery = (todolistId: string) => {
const enabled = todolistIds && todolistIds.length > 0; return useQuery({
return useQueries({ queryKey: ["tasks", todolistId],
queries: todolistIds.map((todolistId) => { queryFn: () =>
return { getTask(todolistId).then((res) => {
queryKey: ["tasks", todolistId], return {
queryFn: () => data: res.data,
getTask(todolistId).then((res) => { todolistId,
return { };
data: res.data, }),
todolistId,
};
}),
enabled: enabled,
};
}),
}); });
}; };
@@ -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) => { export const deleteTodolist = (todolistId: string) => {
return instance.delete(`todo-lists/${todolistId}`); return instance.delete(`todo-lists/${todolistId}`);
}; };
export const createTask = (todolistId: string, title: string) => {
return instance.post(`todo-lists/${todolistId}/tasks`, { title });
};