-
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.
Merge pull request #180 from sohosai/feat/committee-edit-project
feat: 企画編集ページ
- Loading branch information
Showing
11 changed files
with
342 additions
and
28 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
38 changes: 38 additions & 0 deletions
38
src/app/committee/projects/[project_id]/edit/ProjectCategoryEditor.tsx
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,38 @@ | ||
"use client"; | ||
import { ProjectCategoryFormatter } from "@/components/ProjectCategoryFormatter"; | ||
import { projectCategories } from "@/lib/valibot"; | ||
import { css, cx } from "@styled-system/css"; | ||
import { hstack, visuallyHidden } from "@styled-system/patterns"; | ||
import { UseFormRegisterReturn } from "react-hook-form"; | ||
|
||
export const ProjectCategoryEditor: React.FC<{ register: UseFormRegisterReturn }> = ({ register }) => { | ||
return ( | ||
<div className={hstack({ flexWrap: "wrap" })}> | ||
{projectCategories.map((category) => ( | ||
<label | ||
key={category} | ||
className={cx( | ||
css({ | ||
paddingBlock: 2, | ||
paddingInline: 6, | ||
borderRadius: "2xl", | ||
cursor: "pointer", | ||
color: "gray.600", | ||
backgroundColor: "gray.200", | ||
fontSize: "sm", | ||
fontWeight: "bold", | ||
boxSizing: "border-box", | ||
"&:has(> input:checked)": { | ||
color: "sohosai.purple", | ||
outline: "2px solid ", | ||
backgroundColor: "white", | ||
}, | ||
}), | ||
)}> | ||
<ProjectCategoryFormatter category={category} /> | ||
<input type="radio" value={category} className={visuallyHidden()} {...register} /> | ||
</label> | ||
))} | ||
</div> | ||
); | ||
}; |
181 changes: 181 additions & 0 deletions
181
src/app/committee/projects/[project_id]/edit/ProjectEditForm.tsx
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,181 @@ | ||
"use client"; | ||
import { Button } from "@/components/Button"; | ||
import { basicErrorMessageStyle, basicFormStyle } from "@/components/formFields/styles"; | ||
import { AttributesFormatter } from "@/components/project/AttributesFormatter"; | ||
import { client } from "@/lib/openapi"; | ||
import { UpdateProjectCommitteeSchema, UpdateProjectCommitteeSchemaType, projectAttributes } from "@/lib/valibot"; | ||
import { valibotResolver } from "@hookform/resolvers/valibot"; | ||
import { css } from "@styled-system/css"; | ||
import { hstack, stack, visuallyHidden } from "@styled-system/patterns"; | ||
import { useForm } from "react-hook-form"; | ||
import Arrow from "./three_arrow_left.svg"; | ||
import Image from "next/image"; | ||
import { getNewInvitationId, shareURL } from "@/components/project/ProjectView"; | ||
import { components } from "@/schema"; | ||
import toast from "react-hot-toast"; | ||
import { useRouter } from "next/navigation"; | ||
import { ProjectCategoryEditor } from "./ProjectCategoryEditor"; | ||
export const runtime = "edge"; | ||
|
||
export const ProjectEditForm: React.FC<{ project: components["schemas"]["Project"] }> = ({ project }) => { | ||
const router = useRouter(); | ||
const { | ||
register, | ||
formState: { errors }, | ||
handleSubmit, | ||
} = useForm<UpdateProjectCommitteeSchemaType>({ | ||
resolver: valibotResolver(UpdateProjectCommitteeSchema), | ||
defaultValues: project, | ||
mode: "onBlur", | ||
}); | ||
|
||
const lableAndInputStyle = css({ fontWeight: "bold", "& > input": { fontWeight: "normal", marginTop: 2 } }); | ||
const updateProject = async (data: UpdateProjectCommitteeSchemaType) => { | ||
if (!project) return; | ||
client | ||
.PUT("/projects/{project_id}", { | ||
params: { | ||
path: { | ||
project_id: project.id, | ||
}, | ||
}, | ||
body: data as components["schemas"]["UpdateProject"], | ||
}) | ||
.then((res) => { | ||
if (res.error) { | ||
toast.error("変更を保存できませんでした"); | ||
return; | ||
} | ||
toast.success("変更を保存しました"); | ||
router.push(`/committee/projects/${project.id}`); | ||
}) | ||
.catch(() => toast.error("変更を保存できませんでした")); | ||
}; | ||
|
||
return ( | ||
<form className={stack({ gap: 4 })} onSubmit={handleSubmit(updateProject)}> | ||
<div className={hstack({ flexDirection: "row-reverse" })}> | ||
<Button color="primary" type="submit"> | ||
保存 | ||
</Button> | ||
</div> | ||
<label className={lableAndInputStyle}> | ||
企画名 | ||
<input | ||
className={basicFormStyle()} | ||
placeholder="20文字以内で入力" | ||
{...register("title", { value: project?.title })} | ||
/> | ||
<p className={css({ color: "gray.400", fontWeight: "normal" })}> | ||
※絵文字不可。半角全角英数字・半角記号は3字で仮名2文字にカウントします。 | ||
</p> | ||
{errors.title && <span className={basicErrorMessageStyle}>{errors.title.message}</span>} | ||
</label> | ||
<label className={lableAndInputStyle}> | ||
企画名(ふりがな) | ||
<input | ||
className={basicFormStyle()} | ||
placeholder="20文字以内で入力" | ||
{...register("kana_title", { value: project?.kana_title })} | ||
/> | ||
{errors.kana_title && <span className={basicErrorMessageStyle}>{errors.kana_title.message}</span>} | ||
</label> | ||
<label className={lableAndInputStyle}> | ||
企画団体名 | ||
<input className={basicFormStyle()} {...register("group_name", { value: project?.group_name })} /> | ||
<p className={css({ color: "gray.400", fontWeight: "normal" })}> | ||
※絵文字不可。半角全角英数字・半角記号は3字で仮名2文字にカウントします。 | ||
</p> | ||
{errors.group_name && <span className={basicErrorMessageStyle}>{errors.group_name.message}</span>} | ||
</label> | ||
<label className={lableAndInputStyle}> | ||
企画団体名(ふりがな) | ||
<input | ||
className={basicFormStyle()} | ||
{...register("kana_group_name", { | ||
value: project?.kana_group_name, | ||
})} | ||
/> | ||
{errors.kana_group_name && <span className={basicErrorMessageStyle}>{errors.kana_group_name.message}</span>} | ||
</label> | ||
<section className={hstack({ justifyContent: "space-between", marginTop: 10 })}> | ||
<span className={css({ fontWeight: "bold", fontSize: "lg" })}>企画責任者</span> | ||
<div className={hstack()}> | ||
<span>{project?.owner_name}</span> | ||
<Image src={Arrow} alt="" /> | ||
<Button | ||
type="button" | ||
color="secondary" | ||
onClick={async () => | ||
shareURL(`${window.location.origin}/invitation/${await getNewInvitationId(project.id, "owner")}`) | ||
}> | ||
変更用URLを発行 | ||
</Button> | ||
</div> | ||
</section> | ||
<section className={hstack({ justifyContent: "space-between" })}> | ||
<span className={css({ fontWeight: "bold", fontSize: "lg" })}>副企画責任者</span> | ||
<div className={hstack()}> | ||
<span>{project?.sub_owner_name ?? "未設定"}</span> | ||
<Image src={Arrow} alt="" /> | ||
<Button | ||
type="button" | ||
color="secondary" | ||
onClick={async () => shareURL(await getNewInvitationId(project.id, "sub_owner"))}> | ||
変更用URLを発行 | ||
</Button> | ||
</div> | ||
</section> | ||
<fieldset className={css({ marginTop: 10 })}> | ||
<div className={hstack({ marginBottom: 4 })}> | ||
<legend>企画区分</legend> | ||
<legend className={css({ fontSize: "sm", color: "gray.500", fontWeight: "bold" })}> | ||
どれか一つを選択してください | ||
</legend> | ||
</div> | ||
<ProjectCategoryEditor register={register("category", { value: project?.category })} /> | ||
</fieldset> | ||
{errors.category && <span className={basicErrorMessageStyle}>{errors.category.message}</span>} | ||
<fieldset className={css({ marginTop: 5 })}> | ||
<div className={hstack({ marginBottom: 4 })}> | ||
<legend>企画属性</legend> | ||
<legend className={css({ fontSize: "sm", color: "gray.500", fontWeight: "bold" })}> | ||
当てはまるものをすべて選択してください | ||
</legend> | ||
</div> | ||
<div className={hstack()}> | ||
{projectAttributes.map((attribute) => ( | ||
<label | ||
key={attribute} | ||
className={css({ | ||
paddingBlock: 2, | ||
paddingInline: 6, | ||
borderRadius: "2xl", | ||
cursor: "pointer", | ||
color: "gray.600", | ||
fontSize: "sm", | ||
outline: "3px solid token(colors.gray.300)", | ||
fontWeight: "bold", | ||
boxSizing: "border-box", | ||
"&:has(> input:checked)": { | ||
color: "sohosai.purple", | ||
outline: "2px solid ", | ||
backgroundColor: "white", | ||
}, | ||
})}> | ||
<AttributesFormatter attribute={attribute} /> | ||
<input | ||
type="checkbox" | ||
value={attribute} | ||
defaultChecked={project.attributes.includes(attribute as components["schemas"]["ProjectAttribute"])} | ||
{...register("attributes")} | ||
className={visuallyHidden()} | ||
/> | ||
</label> | ||
))} | ||
</div> | ||
</fieldset> | ||
{errors.attributes && <span className={basicErrorMessageStyle}>{errors.attributes.message}</span>} | ||
</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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
"use client"; | ||
|
||
import { assignType } from "@/lib/openapi"; | ||
import { css } from "@styled-system/css"; | ||
import { container } from "@styled-system/patterns"; | ||
import { NextPage } from "next"; | ||
import useSWR from "swr"; | ||
import Link from "next/link"; | ||
import { ProjectEditForm } from "./ProjectEditForm"; | ||
|
||
export const runtime = "edge"; | ||
|
||
const ProjectEditPage: NextPage<{ params: { project_id: string } }> = ({ params }) => { | ||
const { data: rawProject, isLoading, error } = useSWR(`/projects/${params.project_id}`); | ||
const project = rawProject ? assignType("/projects/{project_id}", rawProject) : undefined; | ||
if (isLoading) { | ||
return; | ||
} | ||
|
||
if (error) { | ||
return <>{error}</>; | ||
} | ||
|
||
if (!project) { | ||
return "企画の読み込みに失敗しました"; | ||
} | ||
|
||
return ( | ||
<main className={container({ maxWidth: "4xl", marginY: 8 })}> | ||
<Link className={css({ color: "sohosai.purple", fontSize: "xs" })} href={`/committee/projects/${project.id}`}> | ||
←企画に戻る | ||
</Link> | ||
<ProjectEditForm project={project} /> | ||
</main> | ||
); | ||
}; | ||
|
||
export default ProjectEditPage; |
22 changes: 22 additions & 0 deletions
22
src/app/committee/projects/[project_id]/edit/three_arrow_left.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
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.