-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement form detail and edit
- Loading branch information
Showing
12 changed files
with
416 additions
and
217 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
import { SubmitHandler, useForm } from "react-hook-form"; | ||
import { useState } from "react"; | ||
import { useRouter } from "next/navigation"; | ||
import { css } from "@styled-system/css"; | ||
import toast from "react-hot-toast"; | ||
|
||
import { client } from "@/lib/openapi"; | ||
import { deleteAllUploadedFiles, postFiles } from "@/lib/postFile"; | ||
|
||
import { components } from "@/schema"; | ||
import { FormItems, FileErrorsType, FormFieldsType, FilesFormType } from "./FormItems"; | ||
|
||
import { buttonStyle } from "@/recipes/button"; | ||
import { sosFileType } from "@/lib/file"; | ||
|
||
interface Props { | ||
form: components["schemas"]["Form"]; | ||
answerId: string; | ||
answerItems: FormFieldsType | undefined; | ||
editable: boolean; | ||
} | ||
|
||
export const Form = ({ form, answerId, answerItems, editable }: Props) => { | ||
const router = useRouter(); | ||
const onSubmit: SubmitHandler<FormFieldsType> = async (data) => { | ||
if (Array.from(fileErrors).some((v) => v[1])) { | ||
toast.error(`正しいファイルをアップロードしてください`); | ||
return; | ||
} | ||
|
||
if (!form) { | ||
toast.error("申請の読み込みが終わってから送信してください"); | ||
return; | ||
} | ||
|
||
const fileIds = await postFiles("private", files); | ||
if (!fileIds) { | ||
toast.error("ファイルのアップロード中にエラーが発生しました"); | ||
return; | ||
} | ||
|
||
type formAnswerItems = components["schemas"]["CreateFormAnswer"]["items"]; | ||
const items: formAnswerItems = form.items.flatMap((item): formAnswerItems[number] | [] => { | ||
const value = (() => { | ||
switch (item.type) { | ||
case "string": | ||
return data[item.id] || null; | ||
case "int": | ||
const datum = data[item.id]; | ||
return datum ? parseInt(datum ?? "") : null; | ||
case "file": | ||
return fileIds[item.id] || null; | ||
case "choose_many": | ||
const options = JSON.parse(String(data[item.id] ?? "[]")) as string[]; | ||
return options.length ? options : null; | ||
default: | ||
return data[item.id] || null; | ||
} | ||
})(); | ||
|
||
return value | ||
? { | ||
item_id: item.id, | ||
type: item.type, | ||
value: value, | ||
} | ||
: []; | ||
}); | ||
|
||
if (answerItems) { | ||
client | ||
.PUT("/form-answers/{form_answer_id}", { | ||
params: { | ||
path: { | ||
form_answer_id: answerId, | ||
}, | ||
}, | ||
body: { | ||
form_id: form.id, | ||
items: items, | ||
}, | ||
}) | ||
.then(async ({ error }) => { | ||
if (error) { | ||
toast.error(`申請の修正に失敗しました`); | ||
await deleteAllUploadedFiles(fileIds); | ||
return; | ||
} | ||
toast.success("申請の修正に成功しました"); | ||
router.push("/forms"); | ||
}) | ||
.catch(async () => { | ||
toast.error(`申請の修正内容の送信中にエラーが発生しました`); | ||
await deleteAllUploadedFiles(fileIds); | ||
}); | ||
} else { | ||
client | ||
.POST("/form-answers", { | ||
body: { | ||
form_id: form.id, | ||
items: items, | ||
}, | ||
}) | ||
.then(async ({ error }) => { | ||
if (error) { | ||
toast.error(`申請の送信に失敗しました`); | ||
await deleteAllUploadedFiles(fileIds); | ||
return; | ||
} | ||
toast.success("申請の送信に成功しました"); | ||
router.push("/forms"); | ||
}) | ||
.catch(async () => { | ||
toast.error(`申請の送信中にエラーが発生しました`); | ||
await deleteAllUploadedFiles(fileIds); | ||
}); | ||
} | ||
}; | ||
|
||
const fileFormErrors: FileErrorsType = new Map( | ||
form?.items | ||
.filter((item) => { | ||
item.type === "file"; | ||
}) | ||
.map((item) => [item.id, null]), | ||
); | ||
const [fileErrors, setFileErrors] = useState(fileFormErrors); | ||
|
||
const filesState: FilesFormType = new Map( | ||
form?.items | ||
.filter((item) => item.type === "file") | ||
.map((item) => { | ||
if (answerItems && answerItems[item.id]) { | ||
const dataTransfer = new DataTransfer(); | ||
(answerItems[item.id] as unknown as string[]).forEach((fileId) => { | ||
const file = new File([], fileId, { type: sosFileType }); | ||
dataTransfer.items.add(file); | ||
}); | ||
return [item.id, dataTransfer.files]; | ||
} else { | ||
return [item.id, null]; | ||
} | ||
}), | ||
); | ||
const [files, setFiles] = useState(filesState); | ||
const { | ||
register, | ||
getValues, | ||
setValue, | ||
handleSubmit, | ||
formState: { errors }, | ||
} = useForm({ mode: "onBlur", defaultValues: answerItems }); | ||
|
||
return ( | ||
<form | ||
onSubmit={handleSubmit(onSubmit)} | ||
className={css({ | ||
display: "flex", | ||
flexDirection: "column", | ||
rowGap: 3, | ||
})}> | ||
<FormItems | ||
items={form.items} | ||
getValues={getValues} | ||
setValue={setValue} | ||
register={register} | ||
disabled={!!answerItems && !editable} | ||
errors={errors} | ||
files={files} | ||
setFiles={setFiles} | ||
setFileErrors={setFileErrors} | ||
/> | ||
{(editable || !answerItems) && ( | ||
<button className={buttonStyle({ visual: "solid", color: "purple" })}>{!answerItems ? "送信" : "更新"}</button> | ||
)} | ||
</form> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.