diff --git a/src/app/[slug]/[date]/page.tsx b/src/app/[slug]/[date]/page.tsx
index e66bb19..98c2bca 100644
--- a/src/app/[slug]/[date]/page.tsx
+++ b/src/app/[slug]/[date]/page.tsx
@@ -42,7 +42,7 @@ export default async function Page({ params }: Props) {
)}
-
+
diff --git a/src/app/_actions/taskActions.ts b/src/app/_actions/taskActions.ts
new file mode 100644
index 0000000..a4f81fc
--- /dev/null
+++ b/src/app/_actions/taskActions.ts
@@ -0,0 +1,26 @@
+'use server';
+
+import { API_TASK } from '../_constants/apiUrls';
+import { apiPost } from '~/libs/apiClient';
+import { Task } from '~/domains/Task';
+
+export const postTask = async ({
+ body,
+ title,
+ dueDate,
+ objectiveId,
+}: {
+ body: string;
+ title: string;
+ dueDate: Date;
+ objectiveId: string;
+}) => {
+ return await apiPost<{ task: Task }>(API_TASK(), {
+ body: JSON.stringify({
+ body,
+ title,
+ dueDate,
+ objectiveId,
+ }),
+ });
+};
diff --git a/src/app/_components/domains/Nippo/NippoEditor/NippoEditor.tsx b/src/app/_components/domains/Nippo/NippoEditor/NippoEditor.tsx
index 6b9570d..f88f9c9 100644
--- a/src/app/_components/domains/Nippo/NippoEditor/NippoEditor.tsx
+++ b/src/app/_components/domains/Nippo/NippoEditor/NippoEditor.tsx
@@ -3,7 +3,7 @@
import { FC, useCallback } from 'react';
import { postNippo } from '~/app/_actions/nippoActions';
import { Nippo } from '~/domains/Nippo';
-import { Editor } from '~/app/_components/uiParts/Editor';
+import { DebounceEditor } from '~/app/_components/uiParts/Editor/DebounceEditor';
type Props = {
objectiveId: string;
@@ -19,5 +19,5 @@ export const NippoEditor: FC = ({ objectiveId, nippo, date }) => {
[date, objectiveId],
);
- return ;
+ return ;
};
diff --git a/src/app/_components/domains/Task/CreateTaskModal/CreateTaskModal.tsx b/src/app/_components/domains/Task/CreateTaskModal/CreateTaskModal.tsx
index 9a41969..c6b9cd1 100644
--- a/src/app/_components/domains/Task/CreateTaskModal/CreateTaskModal.tsx
+++ b/src/app/_components/domains/Task/CreateTaskModal/CreateTaskModal.tsx
@@ -1,28 +1,89 @@
'use client';
-import { FC, useCallback } from 'react';
-import { Input, Modal, ModalBody, ModalContent } from '@nextui-org/react';
+import { FC, useCallback, useState } from 'react';
+import { Button, Input, Modal, ModalBody, ModalContent, ModalFooter } from '@nextui-org/react';
+import { Controller, SubmitHandler, useForm } from 'react-hook-form';
import { TaskEditor } from '../TaskEditor';
-import { Task } from '~/domains/Task';
+import { postTask } from '~/app/_actions/taskActions';
type Props = {
isOpen: boolean;
onOpenChange: () => void;
- currentTask?: Task;
+ objectiveId: string;
};
-export const CreateModal: FC = ({ isOpen, onOpenChange, currentTask }) => {
+interface IFormInput {
+ title: string;
+ body: string;
+}
+
+export const CreateModal: FC = ({ isOpen, onOpenChange, objectiveId }) => {
+ const [isLoading, setIsLoading] = useState(false);
+
+ const { control, formState, getValues, handleSubmit, reset } = useForm({
+ defaultValues: {
+ title: '',
+ body: '',
+ },
+ });
+
+ console.log(getValues().body);
+
const handleOpenChange = useCallback(() => {
+ reset();
onOpenChange();
- }, [onOpenChange]);
+ }, [onOpenChange, reset]);
+
+ const onSubmit: SubmitHandler = useCallback(
+ async (inputData) => {
+ if (isLoading) return;
+ setIsLoading(true);
+ postTask({ title: inputData.title, body: inputData.body, dueDate: new Date(), objectiveId })
+ .catch((error) => {
+ // TODO: 本来はコンソールに出すのではなく、ユーザーにエラーを通知する
+ console.error(error);
+ })
+ .then(() => {
+ handleOpenChange();
+ })
+ .finally(() => {
+ setIsLoading(false);
+ });
+ },
+ [handleOpenChange, isLoading, objectiveId],
+ );
return (
-
-
+ (
+
+ )}
+ />
+ field.onChange(body)} />}
+ />
+
+
+
);
diff --git a/src/app/_components/domains/Task/TaskEditor/TaskEditor.tsx b/src/app/_components/domains/Task/TaskEditor/TaskEditor.tsx
index d7f6008..3898019 100644
--- a/src/app/_components/domains/Task/TaskEditor/TaskEditor.tsx
+++ b/src/app/_components/domains/Task/TaskEditor/TaskEditor.tsx
@@ -1,17 +1,12 @@
'use client';
-import { FC, useCallback } from 'react';
+import { FC } from 'react';
import { Editor } from '~/app/_components/uiParts/Editor';
-import { Task } from '~/domains/Task';
type Props = {
- task?: Task;
+ onChangeText: (body: string) => Promise;
};
-export const TaskEditor: FC = ({ task }) => {
- const handleEditorChange = useCallback(async (body: string) => {
- console.log(body);
- }, []);
-
- return ;
+export const TaskEditor: FC = ({ onChangeText }) => {
+ return ;
};
diff --git a/src/app/_components/domains/Task/TaskList/TaskList.tsx b/src/app/_components/domains/Task/TaskList/TaskList.tsx
index b04c476..538a932 100644
--- a/src/app/_components/domains/Task/TaskList/TaskList.tsx
+++ b/src/app/_components/domains/Task/TaskList/TaskList.tsx
@@ -5,7 +5,11 @@ import { FC } from 'react';
import { CreateModal } from '../CreateTaskModal';
import { Icon } from '~/app/_components/uiParts/icons';
-export const TaskList: FC = () => {
+type Props = {
+ objectiveId: string;
+};
+
+export const TaskList: FC = ({ objectiveId }) => {
const { isOpen, onOpen, onOpenChange } = useDisclosure();
return (
@@ -17,7 +21,7 @@ export const TaskList: FC = () => {
} onClick={() => onOpen()}>
タスクの追加
-
+
);
};
diff --git a/src/app/_components/uiParts/Editor/DebounceEditor.tsx b/src/app/_components/uiParts/Editor/DebounceEditor.tsx
new file mode 100644
index 0000000..ae7b14b
--- /dev/null
+++ b/src/app/_components/uiParts/Editor/DebounceEditor.tsx
@@ -0,0 +1,31 @@
+'use client';
+
+import './styles.scss';
+
+import { useEffect, useState, FC, useCallback } from 'react';
+import { Editor } from './Editor';
+import { useDebounce } from '~/libs/useDebounce';
+
+type Props = {
+ body?: string;
+ placeholder: string;
+ onChange: (body: string) => Promise;
+};
+
+export const DebounceEditor: FC = ({ body, placeholder, onChange }) => {
+ const [inputText, setInputText] = useState();
+ const debouncedInputText = useDebounce({ value: inputText, delay: 200 });
+
+ const handleEditorChange = useCallback(
+ async (body: string) => {
+ await onChange(body);
+ },
+ [onChange],
+ );
+
+ useEffect(() => {
+ debouncedInputText && handleEditorChange(debouncedInputText);
+ }, [debouncedInputText, handleEditorChange]);
+
+ return setInputText(body)} />;
+};
diff --git a/src/app/_components/uiParts/Editor/Editor.tsx b/src/app/_components/uiParts/Editor/Editor.tsx
index 6472a2c..fab84e9 100644
--- a/src/app/_components/uiParts/Editor/Editor.tsx
+++ b/src/app/_components/uiParts/Editor/Editor.tsx
@@ -4,36 +4,21 @@ import './styles.scss';
import { Color } from '@tiptap/extension-color';
import { Link } from '@tiptap/extension-link';
-import { useEffect, useState, FC, useCallback } from 'react';
+import { FC } from 'react';
import { EditorContent, useEditor } from '@tiptap/react';
import TextStyle from '@tiptap/extension-text-style';
import Placeholder from '@tiptap/extension-placeholder';
import StarterKit from '@tiptap/starter-kit';
import ListItem from '@tiptap/extension-list-item';
import Heading from '@tiptap/extension-heading';
-import { useDebounce } from '~/libs/useDebounce';
type Props = {
body?: string;
placeholder: string;
- onChange: (body: string) => Promise;
+ onChange: (body: string) => void;
};
export const Editor: FC = ({ body, placeholder, onChange }) => {
- const [inputText, setInputText] = useState();
- const debouncedInputText = useDebounce({ value: inputText, delay: 200 });
-
- const handleEditorChange = useCallback(
- async (body: string) => {
- await onChange(body);
- },
- [onChange],
- );
-
- useEffect(() => {
- debouncedInputText && handleEditorChange(debouncedInputText);
- }, [debouncedInputText, handleEditorChange]);
-
const extensions = [
Color.configure({ types: [TextStyle.name, ListItem.name] }),
Link.configure(),
@@ -60,7 +45,7 @@ export const Editor: FC = ({ body, placeholder, onChange }) => {
content: body,
autofocus: 'end',
onUpdate: ({ editor }) => {
- setInputText(editor.getHTML());
+ onChange(editor.getHTML());
},
editorProps: {
attributes: {
diff --git a/src/app/_constants/apiUrls.ts b/src/app/_constants/apiUrls.ts
index 23c6b6a..90e791b 100644
--- a/src/app/_constants/apiUrls.ts
+++ b/src/app/_constants/apiUrls.ts
@@ -8,3 +8,6 @@ export const API_OBJECTIVE_ME = () => `/api/objectives/me`;
export const API_OBJECTIVE_ID_NIPPO = (_id: string) => `/api/objectives/${_id}/nippos`;
export const API_NIPPO_BY_DATE = (slug: string, data: string) => `/api/nippos/by-date?date=${data}&slug=${slug}`;
+
+export const API_TASK = () => `/api/tasks`;
+export const API_TASK_ID = (id: string) => `/api/tasks/${id}`;