Skip to content

Commit

Permalink
CreateModal の実装と表示
Browse files Browse the repository at this point in the history
  • Loading branch information
itizawa committed Dec 13, 2023
1 parent cc131e3 commit 2a22f08
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
'use client';

import { FC, useCallback, useState } from 'react';
import { Button, Input, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, Textarea } from '@nextui-org/react';
import { Controller, SubmitHandler, useForm } from 'react-hook-form';
import { Task } from '~/domains/Task';

type Props = {
isOpen: boolean;
onOpenChange: () => void;
currentTask?: Task;
};

interface IFormInput {
title: string;
body: string;
}

export const CreateModal: FC<Props> = ({ isOpen, onOpenChange, currentTask }) => {
const [isLoading, setIsLoading] = useState(false);

const { control, handleSubmit, reset } = useForm<IFormInput>({
defaultValues: {
title: currentTask?.title,
body: currentTask?.body,
},
});

const handleOpenChange = useCallback(() => {
reset();
onOpenChange();
}, [onOpenChange, reset]);

const onSubmit: SubmitHandler<IFormInput> = useCallback(async () => {
if (isLoading) return;
setIsLoading(true);
new Promise((resolve) => setTimeout(resolve, 1000))
.catch((error) => {
// TODO: 本来はコンソールに出すのではなく、ユーザーにエラーを通知する
console.error(error);
})
.then(() => {
handleOpenChange();
})
.finally(() => {
setIsLoading(false);
});
}, [handleOpenChange, isLoading]);

return (
<Modal isOpen={isOpen} onOpenChange={handleOpenChange} placement="center" hideCloseButton size="xl">
<ModalContent>
<form onSubmit={handleSubmit(onSubmit)}>
<ModalHeader>タスクを{currentTask ? '編集' : '作成'}する</ModalHeader>
<ModalBody>
<Controller
name="title"
control={control}
render={({ field, fieldState }) => (
<Input
{...field}
label="タイトル"
isInvalid={fieldState.isDirty && field.value.length === 0}
errorMessage={fieldState.isDirty && field.value.length === 0 && 'タイトルを入力してください'}
/>
)}
/>
<Controller
name="body"
control={control}
render={({ field, fieldState }) => (
<Textarea
{...field}
label="説明"
isInvalid={fieldState.isDirty && field.value.length === 0}
errorMessage={fieldState.isDirty && field.value.length === 0 && 'タイトルを入力してください'}
/>
)}
/>
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={handleSubmit(onSubmit)} isLoading={isLoading}>
タスクを作成
</Button>
</ModalFooter>
</form>
</ModalContent>
</Modal>
);
};
1 change: 1 addition & 0 deletions src/app/_components/domains/Task/CreateTaskModal/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { CreateModal } from './CreateTaskModal';
9 changes: 7 additions & 2 deletions src/app/_components/domains/Task/TaskList/TaskList.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
'use client';

import { Button, Card } from '@nextui-org/react';
import { Button, Card, useDisclosure } from '@nextui-org/react';
import { FC } from 'react';
import { CreateModal } from '../CreateTaskModal';
import { Icon } from '~/app/_components/uiParts/icons';

export const TaskList: FC = () => {
const { isOpen, onOpen, onOpenChange } = useDisclosure();

return (
<div className="w-full">
<p className="text-md font-bold mb-[16px] text-gray-700">タスク一覧</p>
<Card className="md:p-[8px] p-[4px] flex flex-col rounded-[8px]" shadow="none" radius="none">
ここにタスク一覧が表示されます
</Card>
<Button className="mt-[8px]" size="sm" color="primary" variant="light" startContent={<Icon icon="PLUS" />}>
<Button className="mt-[8px]" size="sm" color="primary" variant="light" startContent={<Icon icon="PLUS" />} onClick={() => onOpen()}>
タスクの追加
</Button>
<CreateModal isOpen={isOpen} onOpenChange={onOpenChange} />
</div>
);
};

0 comments on commit 2a22f08

Please sign in to comment.