Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion client/src/components/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,9 @@ export const Calendar = ({ project, myGuestId, mySlotsRef, editMode }: Props) =>
);
}
if (info.event.id === MY_EVENT) {
return <div className="h-full w-full text-gray-600 overflow-hidden">{info.timeText}</div>;
return (
<div className="h-full w-full text-gray-600 overflow-hidden">{`${dayjs(info.event.start).format("HH:mm")} - ${dayjs(info.event.end).format("HH:mm")}`}</div>
);
}
}, []);

Expand Down
4 changes: 1 addition & 3 deletions client/src/pages/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ function ProjectDashboard({ involvedProjects }: { involvedProjects: InvolvedProj
</NavLink>
</div>

{involvedProjects.length > 0 ? (
{involvedProjects.length > 0 && (
<div className="space-y-8">
{/* All Projects */}
<section>
Expand All @@ -70,8 +70,6 @@ function ProjectDashboard({ involvedProjects }: { involvedProjects: InvolvedProj
</div>
</section>
</div>
) : (
<EmptyState />
)}
</div>
</div>
Expand Down
87 changes: 70 additions & 17 deletions client/src/pages/Project.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import { zodResolver } from "@hookform/resolvers/zod";
import dayjs from "dayjs";
import { useEffect, useState } from "react";
import { useFieldArray, useForm } from "react-hook-form";
import { HiClipboardCheck, HiClipboardCopy, HiOutlineCheckCircle, HiOutlineExclamationCircle } from "react-icons/hi";
import {
HiClipboardCheck,
HiClipboardCopy,
HiInformationCircle,
HiOutlineCheckCircle,
HiOutlineExclamationCircle,
} from "react-icons/hi";
import { NavLink, useNavigate, useParams } from "react-router";
import type { z } from "zod";
import { editReqSchema, projectReqSchema, projectResSchema } from "../../../common/schema";
Expand Down Expand Up @@ -36,24 +42,30 @@ export default function ProjectPage() {
} | null>(null);

const [copied, setCopied] = useState(false);
const [isInfoExpanded, setIsInfoExpanded] = useState(!eventId); // 新規作成時は展開、編集時は折りたたみ

const {
register,
handleSubmit,
control,
reset,
trigger,
formState: { errors, isValid, isDirty },
} = useForm<FormSchemaType>({
resolver: zodResolver(formSchema),
mode: "onChange",
defaultValues: {
name: "",
startDate: "",
endDate: "",
startDate: eventId ? "" : dayjs().format("YYYY-MM-DD"),
endDate: eventId ? "" : dayjs().add(6, "day").format("YYYY-MM-DD"),
allowedRanges: [{ startTime: "00:00", endTime: "23:45" }],
},
});

const handleFieldFocus = () => {
trigger("name");
};

const { fields, replace } = useFieldArray({
control,
name: "allowedRanges",
Expand All @@ -80,8 +92,8 @@ export default function ProjectPage() {
setSubmitLoading(true);

// 日付をISO形式に変換
const startDateTime = new Date(`${data.startDate}T00:00:00.000Z`).toISOString();
const endDateTime = new Date(`${data.endDate}T23:59:59.999Z`).toISOString();
const startDateTime = new Date(`${data.startDate}T00:00:00.000`).toISOString();
const endDateTime = new Date(`${data.endDate}T23:59:59.999`).toISOString();

// range もISO形式に変換
const rangeWithDateTime = data.allowedRanges?.map((range) => ({
Expand Down Expand Up @@ -184,13 +196,43 @@ export default function ProjectPage() {
<input
{...register("name")}
id="input-name"
className="input w-full text-base"
className={`input w-full text-base ${errors.name ? "input-error border-red-500" : ""}`}
placeholder="イベント名"
onBlur={() => trigger("name")}
/>
{errors.name && <p className="text-red-500">{errors.name.message}</p>}
{errors.name && <p className="text-red-500 text-sm mt-1">{errors.name.message}</p>}
</div>
{!project || (project && project.guests.length === 0) ? (
<>
<div className="collapse collapse-arrow bg-blue-50 border border-blue-200 mb-4">
<input
type="checkbox"
checked={isInfoExpanded}
onChange={(e) => setIsInfoExpanded(e.target.checked)}
/>
<div className="collapse-title text-sm font-medium text-primary flex items-center gap-2">
<HiInformationCircle className="w-5 h-5" />
開始日・終了日/時間帯について
</div>
<div className="collapse-content text-sm text-primary">
<p>
イツヒマでは、<strong>主催者側で候補日程を設定せずに</strong>日程調整します。
<br />
ここでは、参加者の日程を知りたい日付の範囲と時間帯の範囲を設定してください。
<br />
詳しくは、
<a
href="https://utcode.notion.site/1e4ca5f557bc80f2b697ca7b9342dc89?pvs=4"
target="_blank"
rel="noreferrer noopener"
className="link"
>
使い方ページ
</a>
をご覧ください。
</p>
</div>
</div>
<div className="flex gap-2">
<div className="flex-1">
<label htmlFor="input-start" className="text-sm text-gray-400">
Expand All @@ -200,24 +242,31 @@ export default function ProjectPage() {
type="date"
{...register("startDate")}
id="input-start"
className="input w-full text-base"
className={`input w-full text-base ${errors.startDate ? "input-error border-red-500" : ""}`}
onFocus={handleFieldFocus}
/>
{errors.startDate && <p className="text-red-500">{errors.startDate.message}</p>}
{errors.startDate && <p className="text-red-500 text-sm mt-1">{errors.startDate.message}</p>}
</div>
<div className="flex-1">
<label htmlFor="input-end" className="text-sm text-gray-400">
終了日
</label>
<input type="date" {...register("endDate")} id="input-end" className="input w-full text-base" />
{errors.endDate && <p className="text-red-500">{errors.endDate.message}</p>}
<input
type="date"
{...register("endDate")}
id="input-end"
className={`input w-full text-base ${errors.endDate ? "input-error border-red-500" : ""}`}
onFocus={handleFieldFocus}
/>
{errors.endDate && <p className="text-red-500 text-sm mt-1">{errors.endDate.message}</p>}
</div>
</div>
<fieldset>
<legend className="text-sm text-gray-400">時間帯</legend>
<div className="flex gap-2 items-center">
<div className="flex-1 flex gap-1">
<select
className="input flex-1 text-base"
className={`input flex-1 text-base ${errors.allowedRanges ? "input-error border-red-500" : ""}`}
value={fields[0].startTime.split(":")[0]}
onChange={(e) => {
replace([
Expand All @@ -227,6 +276,7 @@ export default function ProjectPage() {
},
]);
}}
onFocus={handleFieldFocus}
>
<option value="" disabled>
Expand All @@ -238,7 +288,7 @@ export default function ProjectPage() {
))}
</select>
<select
className="input flex-1 text-base"
className={`input flex-1 text-base ${errors.allowedRanges ? "input-error border-red-500" : ""}`}
value={fields[0].startTime.split(":")[1]}
onChange={(e) => {
replace([
Expand All @@ -248,6 +298,7 @@ export default function ProjectPage() {
},
]);
}}
onFocus={handleFieldFocus}
>
<option value="" disabled>
Expand All @@ -262,7 +313,7 @@ export default function ProjectPage() {
<span>〜</span>
<div className="flex-1 flex gap-1">
<select
className="input flex-1 text-base"
className={`input flex-1 text-base ${errors.allowedRanges ? "input-error border-red-500" : ""}`}
value={fields[0].endTime.split(":")[0]}
onChange={(e) => {
replace([
Expand All @@ -272,6 +323,7 @@ export default function ProjectPage() {
},
]);
}}
onFocus={handleFieldFocus}
>
<option value="" disabled>
Expand All @@ -283,7 +335,7 @@ export default function ProjectPage() {
))}
</select>
<select
className="input flex-1 text-base"
className={`input flex-1 text-base ${errors.allowedRanges ? "input-error border-red-500" : ""}`}
value={fields[0].endTime.split(":")[1]}
onChange={(e) => {
replace([
Expand All @@ -293,6 +345,7 @@ export default function ProjectPage() {
},
]);
}}
onFocus={handleFieldFocus}
>
<option value="" disabled>
Expand All @@ -306,7 +359,7 @@ export default function ProjectPage() {
</div>
</div>
{errors.allowedRanges && typeof errors.allowedRanges?.message === "string" && (
<p className="text-red-500">{errors.allowedRanges.message}</p>
<p className="text-red-500 text-sm mt-1">{errors.allowedRanges.message}</p>
)}
</fieldset>
</>
Expand All @@ -329,7 +382,7 @@ export default function ProjectPage() {
if (!response.ok) {
throw new Error("削除に失敗しました。");
}
navigate("/");
navigate("/home");
setToast({
message: "イベントを削除しました。",
variant: "success",
Expand Down
2 changes: 1 addition & 1 deletion server/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ model Project {
id String @id @db.VarChar(21)
name String
/// 注: 日付部分のみ利用。時間は考慮しない。
startDate DateTime
startDate DateTime
/// 注: 日付部分のみ利用。時間は考慮しない。
endDate DateTime
/// 注: 現在は 1 つのみ設定可能
Expand Down
17 changes: 10 additions & 7 deletions server/src/routes/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@ router.post("/", validateRequest({ body: projectReqSchema }), async (req, res) =
data: {
id: nanoid(),
name: data.name,
startDate: data.startDate,
endDate: data.endDate,
startDate: new Date(data.startDate),
endDate: new Date(data.endDate),
allowedRanges: {
create: data.allowedRanges,
create: data.allowedRanges.map((range) => ({
startTime: new Date(range.startTime),
endTime: new Date(range.endTime),
})),
},
hosts: {
create: {
Expand Down Expand Up @@ -206,13 +209,13 @@ router.put(
? { name } // ゲストがいれば名前だけ
: {
name,
startDate,
endDate,
startDate: startDate ? new Date(startDate) : undefined,
endDate: endDate ? new Date(endDate) : undefined,
allowedRanges: {
deleteMany: {}, // 既存削除
create: allowedRanges?.map((r) => ({
startTime: r.startTime,
endTime: r.endTime,
startTime: new Date(r.startTime),
endTime: new Date(r.endTime),
})),
},
},
Expand Down