+ {participationFields.map((field, index) => (
+
+
{
- const newOptions = [...participationOptions];
- newOptions[index].color = e.target.value;
- setParticipationOptions(newOptions);
- }}
+ {...register(`participationOptions.${index}.color`)}
+ defaultValue={field.color}
className="h-10 w-10 cursor-pointer rounded border-0"
/>
{
- const newOptions = [...participationOptions];
- newOptions[index].label = e.target.value;
- setParticipationOptions(newOptions);
- }}
+ {...register(`participationOptions.${index}.label`)}
+ defaultValue={field.label}
placeholder="参加形態名(例:対面、オンライン)"
className="input input-bordered flex-1 text-base"
/>
From 79e2c6d5090a6c919bd1ba2635eb48bc703fcb4d Mon Sep 17 00:00:00 2001
From: nakaterm <104970808+nakaterm@users.noreply.github.com>
Date: Sat, 22 Nov 2025 18:49:46 +0900
Subject: [PATCH 04/14] =?UTF-8?q?=E3=82=AB=E3=83=A9=E3=83=BC=E3=83=91?=
=?UTF-8?q?=E3=83=AC=E3=83=83=E3=83=88=E3=82=92=E8=AA=BF=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
common/colors.ts | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/common/colors.ts b/common/colors.ts
index eff2ec5..39b3d60 100644
--- a/common/colors.ts
+++ b/common/colors.ts
@@ -1,12 +1,9 @@
export const PREDEFINED_COLORS = [
- "#4ECDC4", // 青緑
- "#45B7D1", // 水色
- "#96CEB4", // 緑
- "#FFEAA7", // 黄
- "#DDA0DD", // 紫
- "#87CEEB", // スカイブルー
- "#9B59B6", // 濃い紫
- "#3498DB", // 青
+ "#FF9500", // オレンジ
+ "#10B981", // 緑
+ "#3B82F6", // 青
+ "#A855F7", // 紫
+ "#EC4899", // ピンク
];
export const DEFAULT_PARTICIPATION_OPTION = {
From 364629ac909c2c4b5f6defb2c853c22e28666d40 Mon Sep 17 00:00:00 2001
From: nakaterm <104970808+nakaterm@users.noreply.github.com>
Date: Sat, 22 Nov 2025 18:58:42 +0900
Subject: [PATCH 05/14] =?UTF-8?q?=E3=83=A9=E3=83=99=E3=83=AB=E7=A9=BA?=
=?UTF-8?q?=E6=AC=84=E6=99=82=E3=81=AE=E3=83=A1=E3=83=83=E3=82=BB=E3=83=BC?=
=?UTF-8?q?=E3=82=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
client/src/pages/Project.tsx | 61 +++++++++++++++++++++++-------------
1 file changed, 39 insertions(+), 22 deletions(-)
diff --git a/client/src/pages/Project.tsx b/client/src/pages/Project.tsx
index c53224e..6606011 100644
--- a/client/src/pages/Project.tsx
+++ b/client/src/pages/Project.tsx
@@ -96,6 +96,7 @@ export default function ProjectPage() {
startDate: eventId ? "" : dayjs().format("YYYY-MM-DD"),
endDate: eventId ? "" : dayjs().add(6, "day").format("YYYY-MM-DD"),
allowedRanges: [{ startTime: "00:00", endTime: "23:45" }],
+ participationOptions: [],
},
});
@@ -444,28 +445,44 @@ export default function ProjectPage() {
{participationFields.map((field, index) => (
-
-
-
-
-
removeParticipation(index)}
- className="btn btn-ghost btn-sm text-error"
- >
- 削除
-
+
+
+
+
+ {
+ // 値を変更していない場合でも空ならエラー表示させるため手動で検証
+ trigger(`participationOptions.${index}.label` as const);
+ }}
+ />
+ removeParticipation(index)}
+ className="btn btn-ghost btn-sm text-error"
+ >
+ 削除
+
+
+ {errors.participationOptions?.[index]?.label && (
+
+ {errors.participationOptions[index]?.label?.message as string}
+
+ )}
+ {errors.participationOptions?.[index]?.color && (
+
+ {errors.participationOptions[index]?.color?.message as string}
+
+ )}
))}
From 33a5e8c18d11237f8f6921856366af9c3aec74f5 Mon Sep 17 00:00:00 2001
From: nakaterm <104970808+nakaterm@users.noreply.github.com>
Date: Sat, 22 Nov 2025 19:08:38 +0900
Subject: [PATCH 06/14] =?UTF-8?q?=E3=83=A9=E3=83=99=E3=83=AB=E5=89=8A?=
=?UTF-8?q?=E9=99=A4=E5=A4=B1=E6=95=97=E6=99=82=E3=81=AE=E3=82=A8=E3=83=A9?=
=?UTF-8?q?=E3=83=BC=E3=83=A1=E3=83=83=E3=82=BB=E3=83=BC=E3=82=B8=E3=82=92?=
=?UTF-8?q?=E8=A1=A8=E7=A4=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
client/src/pages/Project.tsx | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/client/src/pages/Project.tsx b/client/src/pages/Project.tsx
index 6606011..5148232 100644
--- a/client/src/pages/Project.tsx
+++ b/client/src/pages/Project.tsx
@@ -206,11 +206,22 @@ export default function ProjectPage() {
});
setTimeout(() => setToast(null), 3000);
} else {
+ let errorMessage = "更新に失敗しました。";
+ try {
+ const data = await res.json();
+ if (data && typeof data.message === "string" && data.message.trim()) {
+ errorMessage = data.message.trim();
+ } else if (res.status === 403) {
+ errorMessage = "権限がありません。";
+ }
+ } catch (_) {
+ if (res.status === 403) errorMessage = "権限がありません。";
+ }
setToast({
- message: res.status === 403 ? "権限がありません。" : "更新に失敗しました。",
+ message: errorMessage,
variant: "error",
});
- setTimeout(() => setToast(null), 3000);
+ setTimeout(() => setToast(null), 4000);
}
}
};
From f33c4cb0281361b9a95a378fb2e5eeb2b7a903a9 Mon Sep 17 00:00:00 2001
From: nakaterm <104970808+nakaterm@users.noreply.github.com>
Date: Sun, 23 Nov 2025 02:16:33 +0900
Subject: [PATCH 07/14] =?UTF-8?q?=E7=AE=A1=E7=90=86=E3=83=9C=E3=82=BF?=
=?UTF-8?q?=E3=83=B3=E5=89=8A=E9=99=A4=E3=80=81=E7=B7=A8=E9=9B=86=E7=94=BB?=
=?UTF-8?q?=E9=9D=A2=E3=81=8B=E3=82=89=E3=83=97=E3=83=AD=E3=82=B8=E3=82=A7?=
=?UTF-8?q?=E3=82=AF=E3=83=88=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=AB=E6=88=BB?=
=?UTF-8?q?=E3=82=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
client/src/pages/Home.tsx | 45 +++++++++++++-----------------------
client/src/pages/Project.tsx | 12 +++++++---
2 files changed, 25 insertions(+), 32 deletions(-)
diff --git a/client/src/pages/Home.tsx b/client/src/pages/Home.tsx
index 4dbaac0..c9628a6 100644
--- a/client/src/pages/Home.tsx
+++ b/client/src/pages/Home.tsx
@@ -1,6 +1,6 @@
import { hc } from "hono/client";
import { useEffect, useState } from "react";
-import { HiOutlineCalendar, HiOutlineCog, HiOutlinePlus, HiOutlineUser, HiOutlineUsers } from "react-icons/hi";
+import { HiOutlineCalendar, HiOutlinePlus, HiOutlineUser, HiOutlineUsers } from "react-icons/hi";
import { NavLink } from "react-router";
import type { AppType } from "../../../server/src/main";
import Header from "../components/Header";
@@ -112,34 +112,21 @@ function ProjectCard({ project }: { project: BriefProject }) {
aria-label={`「${project.name}」の詳細を見る`}
>
-
-
-
{project.name}
-
- {project.isHost ? (
- <>
-
- 主催者
- >
- ) : (
- <>
-
- 参加者
- >
- )}
-
-
-
- {project.isHost && (
-
e.stopPropagation()}
- className="btn btn-ghost btn-sm px-3 py-1 text-gray-500 transition-all hover:bg-gray-100 hover:text-gray-700"
- >
-
- 管理
-
- )}
+
+
{project.name}
+
+ {project.isHost ? (
+ <>
+
+ 主催者
+ >
+ ) : (
+ <>
+
+ 参加者
+ >
+ )}
+
diff --git a/client/src/pages/Project.tsx b/client/src/pages/Project.tsx
index 5148232..ac02ba0 100644
--- a/client/src/pages/Project.tsx
+++ b/client/src/pages/Project.tsx
@@ -557,9 +557,15 @@ export default function ProjectPage() {
)}
-
- ホームに戻る
-
+ {eventId ? (
+
+ 日程調整に戻る
+
+ ) : (
+
+ ホームに戻る
+
+ )}
イベントを{project ? "更新" : "作成"}する
From ba695845d7fcfdceb1e1d870c0d662f40b72e0cc Mon Sep 17 00:00:00 2001
From: nakaterm <104970808+nakaterm@users.noreply.github.com>
Date: Sun, 23 Nov 2025 03:05:12 +0900
Subject: [PATCH 08/14] =?UTF-8?q?=E3=83=87=E3=83=95=E3=82=A9=E3=83=AB?=
=?UTF-8?q?=E3=83=88=E3=81=AE=20allowedRange=20=E3=82=92=E5=A4=89=E6=9B=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
client/src/pages/Project.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/client/src/pages/Project.tsx b/client/src/pages/Project.tsx
index ac02ba0..b8ce265 100644
--- a/client/src/pages/Project.tsx
+++ b/client/src/pages/Project.tsx
@@ -95,7 +95,7 @@ export default function ProjectPage() {
description: "",
startDate: eventId ? "" : dayjs().format("YYYY-MM-DD"),
endDate: eventId ? "" : dayjs().add(6, "day").format("YYYY-MM-DD"),
- allowedRanges: [{ startTime: "00:00", endTime: "23:45" }],
+ allowedRanges: [{ startTime: "08:00", endTime: "23:00" }],
participationOptions: [],
},
});
From eb84f306ede89e3585ca63cd7e5088d1823d9c6d Mon Sep 17 00:00:00 2001
From: nakaterm <104970808+nakaterm@users.noreply.github.com>
Date: Sun, 23 Nov 2025 04:21:02 +0900
Subject: [PATCH 09/14] =?UTF-8?q?=E5=8F=82=E5=8A=A0=E5=BD=A2=E6=85=8B?=
=?UTF-8?q?=E5=89=8A=E9=99=A4=E3=83=9C=E3=82=BF=E3=83=B3=E3=81=AE=E9=9D=9E?=
=?UTF-8?q?=E6=B4=BB=E6=80=A7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
client/src/pages/Project.tsx | 92 ++++++++++++++++++++----------------
1 file changed, 52 insertions(+), 40 deletions(-)
diff --git a/client/src/pages/Project.tsx b/client/src/pages/Project.tsx
index b8ce265..0fe14e1 100644
--- a/client/src/pages/Project.tsx
+++ b/client/src/pages/Project.tsx
@@ -115,6 +115,7 @@ export default function ProjectPage() {
remove: removeParticipation,
} = useFieldArray({
control,
+ keyName: "fieldId", // RHF 内部のキーの名称。デフォルトの id だと participationOptions の id と衝突するため変更
name: "participationOptions",
});
useEffect(() => {
@@ -455,47 +456,58 @@ export default function ProjectPage() {
参加形態を設定すると、参加者は「対面」「オンライン」などの形態を選んで日程を登録できます。
- {participationFields.map((field, index) => (
-
-
-
-
-
{
- // 値を変更していない場合でも空ならエラー表示させるため手動で検証
- trigger(`participationOptions.${index}.label` as const);
- }}
- />
-
removeParticipation(index)}
- className="btn btn-ghost btn-sm text-error"
- >
- 削除
-
+ {participationFields.map((field, index) => {
+ const hasSlots = project?.guests.some((guest) =>
+ guest.slots.some((slot) => slot.participationOptionId === field.id),
+ );
+ return (
+
+
+
+
+
{
+ // 値を変更していない場合でも空ならエラー表示させるため手動で検証
+ trigger(`participationOptions.${index}.label` as const);
+ }}
+ />
+
+ removeParticipation(index)}
+ className={`btn btn-ghost btn-sm text-error ${hasSlots ? "cursor-not-allowed opacity-40" : ""}`}
+ disabled={hasSlots}
+ >
+ 削除
+
+
+
+ {errors.participationOptions?.[index]?.label && (
+
+ {errors.participationOptions[index]?.label?.message as string}
+
+ )}
+ {errors.participationOptions?.[index]?.color && (
+
+ {errors.participationOptions[index]?.color?.message as string}
+
+ )}
- {errors.participationOptions?.[index]?.label && (
-
- {errors.participationOptions[index]?.label?.message as string}
-
- )}
- {errors.participationOptions?.[index]?.color && (
-
- {errors.participationOptions[index]?.color?.message as string}
-
- )}
-
- ))}
+ );
+ })}
Date: Sun, 23 Nov 2025 04:37:04 +0900
Subject: [PATCH 10/14] =?UTF-8?q?=E6=97=A5=E6=99=82=E3=81=AE=E5=85=A5?=
=?UTF-8?q?=E5=8A=9B=E6=AC=84=E3=81=AE=E9=9D=9E=E6=B4=BB=E6=80=A7=E3=82=82?=
=?UTF-8?q?=E7=B5=B1=E4=B8=80=E7=9A=84=E3=81=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
client/src/pages/Project.tsx | 335 ++++++++++++++++++-----------------
1 file changed, 177 insertions(+), 158 deletions(-)
diff --git a/client/src/pages/Project.tsx b/client/src/pages/Project.tsx
index 0fe14e1..710c751 100644
--- a/client/src/pages/Project.tsx
+++ b/client/src/pages/Project.tsx
@@ -286,170 +286,189 @@ export default function ProjectPage() {
/>
{errors.description && {errors.description.message}
}
- {!project || (project && project.guests.length === 0) ? (
- <>
-
-
setIsInfoExpanded(e.target.checked)}
- />
-
-
- 開始日・終了日/時間帯について
-
-
-
- イツヒマでは、主催者側で候補日程を設定せずに日程調整します。
-
- ここでは、参加者の日程を知りたい日付の範囲と時間帯の範囲を設定してください。
-
- 詳しくは、
-
- 使い方ページ
-
- をご覧ください。
-
-
-
-
-
-
-
- {errors.startDate &&
{errors.startDate.message}
}
-
-
-
-
+
setIsInfoExpanded(e.target.checked)} />
+
+
+ 開始日・終了日/時間帯について
+
+
+
+ イツヒマでは、主催者側で候補日程を設定せずに日程調整します。
+
+ ここでは、参加者の日程を知りたい日付の範囲と時間帯の範囲を設定してください。
+
+ 詳しくは、
+
+ 使い方ページ
+
+ をご覧ください。
+
+
+
+
+
0 ? "tooltip tooltip-top flex-1" : "flex-1"}
+ data-tip={
+ project && project.guests.length > 0
+ ? "すでに日程を登録したユーザーがいるため、開始日の編集はできません"
+ : ""
+ }
+ >
+
+
0 ? "cursor-not-allowed opacity-60" : ""}`}
+ onFocus={handleFieldFocus}
+ disabled={!!(project && project.guests.length > 0)}
+ />
+ {errors.startDate &&
{errors.startDate.message}
}
+
+
0 ? "tooltip tooltip-top flex-1" : "flex-1"}
+ data-tip={
+ project && project.guests.length > 0
+ ? "すでに日程を登録したユーザーがいるため、終了日の編集はできません"
+ : ""
+ }
+ >
+
+
0 ? "cursor-not-allowed opacity-60" : ""}`}
+ onFocus={handleFieldFocus}
+ disabled={!!(project && project.guests.length > 0)}
+ />
+ {errors.endDate &&
{errors.endDate.message}
}
+
+
+
+ {errors.allowedRanges && typeof errors.allowedRanges?.message === "string" && (
+
{errors.allowedRanges.message}
+ )}
+
From 53ce1814aa8d7866a3604892ea480452fe1ae157 Mon Sep 17 00:00:00 2001
From: nakaterm <104970808+nakaterm@users.noreply.github.com>
Date: Sun, 23 Nov 2025 04:41:08 +0900
Subject: [PATCH 11/14] =?UTF-8?q?=E5=89=8A=E9=99=A4=E3=83=9C=E3=82=BF?=
=?UTF-8?q?=E3=83=B3=E3=81=AE=E3=82=B9=E3=82=BF=E3=82=A4=E3=83=AB=E3=82=92?=
=?UTF-8?q?=E6=95=B4=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
client/src/pages/Project.tsx | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/client/src/pages/Project.tsx b/client/src/pages/Project.tsx
index 710c751..392b63f 100644
--- a/client/src/pages/Project.tsx
+++ b/client/src/pages/Project.tsx
@@ -9,6 +9,7 @@ import {
HiInformationCircle,
HiOutlineCheckCircle,
HiOutlineExclamationCircle,
+ HiOutlineTrash,
} from "react-icons/hi";
import { NavLink, useNavigate, useParams } from "react-router";
import type { z } from "zod";
@@ -510,7 +511,7 @@ export default function ProjectPage() {
className={`btn btn-ghost btn-sm text-error ${hasSlots ? "cursor-not-allowed opacity-40" : ""}`}
disabled={hasSlots}
>
- 削除
+
@@ -550,7 +551,7 @@ export default function ProjectPage() {
{
if (confirm("本当にこのイベントを削除しますか?")) {
try {
@@ -582,6 +583,7 @@ export default function ProjectPage() {
}
}}
>
+
イベントを削除する
From 42eb87cdb7c4e6fcddff9e7a9e4361f9cce3ab29 Mon Sep 17 00:00:00 2001
From: nakaterm <104970808+nakaterm@users.noreply.github.com>
Date: Sun, 23 Nov 2025 05:09:47 +0900
Subject: [PATCH 12/14] =?UTF-8?q?=E5=8F=82=E5=8A=A0=E5=BD=A2=E6=85=8B?=
=?UTF-8?q?=E3=82=92=E8=A8=AD=E5=AE=9A=E3=81=97=E3=81=AA=E3=81=84=E5=A0=B4?=
=?UTF-8?q?=E5=90=88=E3=81=AE=E3=83=95=E3=83=AD=E3=83=BC=E3=82=92=E6=95=B4?=
=?UTF-8?q?=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
client/src/pages/Project.tsx | 168 +++++++++++++++++++---------------
common/validators.ts | 2 +-
server/src/routes/projects.ts | 24 +----
3 files changed, 101 insertions(+), 93 deletions(-)
diff --git a/client/src/pages/Project.tsx b/client/src/pages/Project.tsx
index 392b63f..86331ce 100644
--- a/client/src/pages/Project.tsx
+++ b/client/src/pages/Project.tsx
@@ -13,7 +13,7 @@ import {
} from "react-icons/hi";
import { NavLink, useNavigate, useParams } from "react-router";
import type { z } from "zod";
-import { generateDistinctColor } from "../../../common/colors";
+import { DEFAULT_PARTICIPATION_OPTION, generateDistinctColor } from "../../../common/colors";
import { editReqSchema, projectReqSchema } from "../../../common/validators";
import type { AppType } from "../../../server/src/main";
import Header from "../components/Header";
@@ -80,6 +80,7 @@ export default function ProjectPage() {
const [copied, setCopied] = useState(false);
const [isInfoExpanded, setIsInfoExpanded] = useState(!eventId); // 新規作成時は展開、編集時は折りたたみ
+ const [isParticipationExpanded, setIsParticipationExpanded] = useState(!!eventId); // 新規作成時は折りたたみ、編集時は展開
const {
register,
@@ -97,7 +98,15 @@ export default function ProjectPage() {
startDate: eventId ? "" : dayjs().format("YYYY-MM-DD"),
endDate: eventId ? "" : dayjs().add(6, "day").format("YYYY-MM-DD"),
allowedRanges: [{ startTime: "08:00", endTime: "23:00" }],
- participationOptions: [],
+ participationOptions: eventId
+ ? []
+ : [
+ {
+ id: crypto.randomUUID(),
+ label: DEFAULT_PARTICIPATION_OPTION.label,
+ color: DEFAULT_PARTICIPATION_OPTION.color,
+ },
+ ],
},
});
@@ -470,80 +479,93 @@ export default function ProjectPage() {
{errors.allowedRanges.message}
)}
-
-
-
- 参加形態を設定すると、参加者は「対面」「オンライン」などの形態を選んで日程を登録できます。
-
+
+
setIsParticipationExpanded(e.target.checked)}
+ />
+
参加形態の設定 (任意)
+
+
+
+ 参加形態を設定すると、参加者は「対面」「オンライン」などの形態を選んで日程を登録できます。
+
- {participationFields.map((field, index) => {
- const hasSlots = project?.guests.some((guest) =>
- guest.slots.some((slot) => slot.participationOptionId === field.id),
- );
- return (
-
-
-
-
-
{
- // 値を変更していない場合でも空ならエラー表示させるため手動で検証
- trigger(`participationOptions.${index}.label` as const);
- }}
- />
-
-
removeParticipation(index)}
- className={`btn btn-ghost btn-sm text-error ${hasSlots ? "cursor-not-allowed opacity-40" : ""}`}
- disabled={hasSlots}
- >
-
-
+ {participationFields.map((field, index) => {
+ const hasSlots = project?.guests.some((guest) =>
+ guest.slots.some((slot) => slot.participationOptionId === field.id),
+ );
+ const isLastOption = participationFields.length === 1;
+ const cannotDelete = hasSlots || isLastOption;
+ const tooltipMessage = hasSlots
+ ? "すでにこの参加形態の日程が登録されているため、削除できません"
+ : isLastOption
+ ? "最低1つの参加形態が必要です"
+ : "";
+ return (
+
+
+
+
+
{
+ // 値を変更していない場合でも空ならエラー表示させるため手動で検証
+ trigger(`participationOptions.${index}.label` as const);
+ }}
+ />
+
+ removeParticipation(index)}
+ className={`btn btn-ghost btn-sm text-error ${cannotDelete ? "cursor-not-allowed opacity-40" : ""}`}
+ disabled={cannotDelete}
+ >
+
+
+
+
+ {errors.participationOptions?.[index]?.label && (
+
+ {errors.participationOptions[index]?.label?.message as string}
+
+ )}
+ {errors.participationOptions?.[index]?.color && (
+
+ {errors.participationOptions[index]?.color?.message as string}
+
+ )}
-
- {errors.participationOptions?.[index]?.label && (
-
- {errors.participationOptions[index]?.label?.message as string}
-
- )}
- {errors.participationOptions?.[index]?.color && (
-
- {errors.participationOptions[index]?.color?.message as string}
-
- )}
-
- );
- })}
+ );
+ })}
-
{
- const existingColors = participationFields.map((o) => o.color);
- appendParticipation({
- id: crypto.randomUUID(),
- label: "",
- color: generateDistinctColor(existingColors),
- });
- }}
- className="btn btn-outline btn-sm"
- >
- + 参加形態を追加
-
-
+
{
+ const existingColors = participationFields.map((o) => o.color);
+ appendParticipation({
+ id: crypto.randomUUID(),
+ label: "",
+ color: generateDistinctColor(existingColors),
+ });
+ }}
+ className="btn btn-outline btn-sm"
+ >
+ + 参加形態を追加
+
+
+
+
{project && (
diff --git a/common/validators.ts b/common/validators.ts
index 91ba844..130fbea 100644
--- a/common/validators.ts
+++ b/common/validators.ts
@@ -65,7 +65,7 @@ const baseProjectReqSchema = z.object({
.refine((ranges) => ranges.every(({ startTime, endTime }) => isQuarterHour(startTime) && isQuarterHour(endTime)), {
message: "開始時刻と終了時刻は15分単位で入力してください",
}),
- participationOptions: z.array(participationOptionCreateSchema).optional(),
+ participationOptions: z.array(participationOptionCreateSchema).min(1, "参加形態は最低1つ必要です"),
});
export const projectReqSchema = baseProjectReqSchema.refine(
diff --git a/server/src/routes/projects.ts b/server/src/routes/projects.ts
index eefea22..a74c6bc 100644
--- a/server/src/routes/projects.ts
+++ b/server/src/routes/projects.ts
@@ -1,11 +1,9 @@
-import { randomUUID } from "node:crypto";
import { zValidator } from "@hono/zod-validator";
import dotenv from "dotenv";
import { Hono } from "hono";
import { getSignedCookie, setSignedCookie } from "hono/cookie";
import { nanoid } from "nanoid";
import { z } from "zod";
-import { DEFAULT_PARTICIPATION_OPTION } from "../../../common/colors.js";
import { editReqSchema, projectReqSchema, submitReqSchema } from "../../../common/validators.js";
import { cookieOptions, prisma } from "../main.js";
@@ -25,22 +23,6 @@ const router = new Hono()
try {
const data = c.req.valid("json");
- // 参加形態の処理(指定がない場合はデフォルトを作成)
- const participationOptionsData =
- data.participationOptions && data.participationOptions.length > 0
- ? data.participationOptions.map((opt) => ({
- id: opt.id, // フロントエンドで生成された UUID をそのまま使用
- label: opt.label,
- color: opt.color,
- }))
- : [
- {
- id: randomUUID(), // デフォルト作成時のみサーバーで生成
- label: DEFAULT_PARTICIPATION_OPTION.label,
- color: DEFAULT_PARTICIPATION_OPTION.color,
- },
- ];
-
const event = await prisma.project.create({
data: {
id: nanoid(),
@@ -60,7 +42,11 @@ const router = new Hono()
},
},
participationOptions: {
- create: participationOptionsData,
+ create: data.participationOptions.map((opt) => ({
+ id: opt.id,
+ label: opt.label,
+ color: opt.color,
+ })),
},
},
include: { hosts: true, participationOptions: true },
From 001efc6f9c90c5ae6e121afdd84a2b8d357f4818 Mon Sep 17 00:00:00 2001
From: nakaterm <104970808+nakaterm@users.noreply.github.com>
Date: Sun, 23 Nov 2025 05:15:34 +0900
Subject: [PATCH 13/14] =?UTF-8?q?=E3=82=AB=E3=83=BC=E3=83=89=E3=81=AE?=
=?UTF-8?q?=E6=9E=A0=E7=B7=9A=E3=81=AE=E8=89=B2=E3=81=8C=E6=B6=88=E3=81=88?=
=?UTF-8?q?=E3=82=8B=E3=83=90=E3=82=B0=E4=BF=AE=E6=AD=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
client/src/pages/Home.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/client/src/pages/Home.tsx b/client/src/pages/Home.tsx
index c9628a6..79700df 100644
--- a/client/src/pages/Home.tsx
+++ b/client/src/pages/Home.tsx
@@ -108,7 +108,7 @@ function ProjectCard({ project }: { project: BriefProject }) {
return (
From 584a1ed9a3c576446565f31a2b1c5b6241fec51a Mon Sep 17 00:00:00 2001
From: nakaterm <104970808+nakaterm@users.noreply.github.com>
Date: Sun, 23 Nov 2025 05:25:45 +0900
Subject: [PATCH 14/14] bump hono and related packages
---
package-lock.json | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index f224bda..b3bf946 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1161,9 +1161,10 @@
}
},
"node_modules/@hono/node-server": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.1.tgz",
- "integrity": "sha512-h44e5s+ByUriaRIbeS/C74O8v90m0A95luyYQGMF7KEn96KkYMXO7bZAwombzTpjQTU4e0TkU8U1WBIXlwuwtA==",
+ "version": "1.19.6",
+ "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.6.tgz",
+ "integrity": "sha512-Shz/KjlIeAhfiuE93NDKVdZ7HdBVLQAfdbaXEaoAVO3ic9ibRSLGIQGkcBbFyuLr+7/1D5ZCINM8B+6IvXeMtw==",
+ "license": "MIT",
"engines": {
"node": ">=18.14.1"
},
@@ -1172,9 +1173,10 @@
}
},
"node_modules/@hono/zod-validator": {
- "version": "0.7.2",
- "resolved": "https://registry.npmjs.org/@hono/zod-validator/-/zod-validator-0.7.2.tgz",
- "integrity": "sha512-ub5eL/NeZ4eLZawu78JpW/J+dugDAYhwqUIdp9KYScI6PZECij4Hx4UsrthlEUutqDDhPwRI0MscUfNkvn/mqQ==",
+ "version": "0.7.5",
+ "resolved": "https://registry.npmjs.org/@hono/zod-validator/-/zod-validator-0.7.5.tgz",
+ "integrity": "sha512-n4l4hutkfYU07PzRUHBOVzUEn38VSfrh+UVE5d0w4lyfWDOEhzxIupqo5iakRiJL44c3vTuFJBvcmUl8b9agIA==",
+ "license": "MIT",
"peerDependencies": {
"hono": ">=3.9.0",
"zod": "^3.25.0 || ^4.0.0"
@@ -2583,9 +2585,10 @@
"license": "MIT"
},
"node_modules/hono": {
- "version": "4.9.6",
- "resolved": "https://registry.npmjs.org/hono/-/hono-4.9.6.tgz",
- "integrity": "sha512-doVjXhSFvYZ7y0dNokjwwSahcrAfdz+/BCLvAMa/vHLzjj8+CFyV5xteThGUsKdkaasgN+gF2mUxao+SGLpUeA==",
+ "version": "4.10.6",
+ "resolved": "https://registry.npmjs.org/hono/-/hono-4.10.6.tgz",
+ "integrity": "sha512-BIdolzGpDO9MQ4nu3AUuDwHZZ+KViNm+EZ75Ae55eMXMqLVhDFqEMXxtUe9Qh8hjL+pIna/frs2j6Y2yD5Ua/g==",
+ "license": "MIT",
"engines": {
"node": ">=16.9.0"
}