Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eventの空白をzodでバリデーション #116

Merged
merged 2 commits into from
Dec 11, 2024
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
22 changes: 9 additions & 13 deletions task_yell/src/app/home/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,9 @@ import {
readWantTodos,
updateWantTodo,
} from "@/lib/want-todo";
import {
addMonths,
format,
subMonths,
} from "date-fns";
import { addMonths, format, subMonths } from "date-fns";
import { ja } from "date-fns/locale";
import {
ChevronLeft,
ChevronRight,
} from "lucide-react";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { useRouter } from "next/navigation";
import { useEffect, useMemo, useState } from "react";
import { generateStickyNoteServer } from "./actions";
Expand Down Expand Up @@ -157,6 +150,7 @@ export default function Home() {
newEvent: Event,
notification: { date: Date | null; type: "call" | "push" },
) => {
console.log("addEvent", newEvent);
setEvents([...events, newEvent]);
setIsEventModalOpen(false);
setRemovedStickyNote(null);
Expand Down Expand Up @@ -235,10 +229,12 @@ export default function Home() {
</div>

<div className="w-full lg:w-1/2 pl-2 bg-white dark:bg-gray-800 overflow-auto lg:block hidden">
<WantodoView
newStickyNote={newStickyNote} setNewStickyNote={setNewStickyNote}
<WantodoView
newStickyNote={newStickyNote}
setNewStickyNote={setNewStickyNote}
addStickyNote={addStickyNote}
searchTerm={searchTerm} setSearchTerm={setSearchTerm}
searchTerm={searchTerm}
setSearchTerm={setSearchTerm}
filteredStickyNotes={filteredStickyNotes}
setDraggedStickyNote={setDraggedStickyNote}
generateStickyNote={generateStickyNote}
Expand All @@ -254,7 +250,7 @@ export default function Home() {
updateStickyNote={updateStickyNote}
/>

<CreateEventDialog
<CreateEventDialog
stickyNotes={stickyNotes}
setStickyNotes={setStickyNotes}
isEventModalOpen={isEventModalOpen}
Expand Down
37 changes: 23 additions & 14 deletions task_yell/src/components/calendar-renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type Props = {
draggedStickyNote: StickyNote | null;
deleteStickyNote: (id: string) => void;
setIsEventModalOpen: (isOpen: boolean) => void;
}
};

function getDaysInMonth(date: Date) {
const start = startOfWeek(startOfMonth(date), { weekStartsOn: 0 });
Expand All @@ -42,7 +42,11 @@ function getEventCountForDay(events: Event[], day: Date) {
.length;
}

function getTaskIndicatorStyle(isDarkMode: boolean, todoCount: number, eventCount: number) {
function getTaskIndicatorStyle(
isDarkMode: boolean,
todoCount: number,
eventCount: number,
) {
const count = todoCount + eventCount;
if (count === 0) return "";
const baseColor = isDarkMode ? "bg-red-" : "bg-red-";
Expand All @@ -52,13 +56,16 @@ function getTaskIndicatorStyle(isDarkMode: boolean, todoCount: number, eventCoun
}

export function CalendarRenderer({
todos, events,
currentMonth, selectedDate, handleDateSelect,
todos,
events,
currentMonth,
selectedDate,
handleDateSelect,
isDarkMode,
draggedStickyNote, deleteStickyNote,
setIsEventModalOpen
}: Props
) {
draggedStickyNote,
deleteStickyNote,
setIsEventModalOpen,
}: Props) {
const days = getDaysInMonth(currentMonth);
const weeks = Math.ceil(days.length / 7);

Expand All @@ -78,7 +85,8 @@ export function CalendarRenderer({
const weekDays = days.slice(weekIndex * 7, (weekIndex + 1) * 7);
const maxEventsInWeek = Math.max(
...weekDays.map(
(day) => getTodoCountForDay(todos, day) + getEventCountForDay(events, day),
(day) =>
getTodoCountForDay(todos, day) + getEventCountForDay(events, day),
),
);
const weekHeight =
Expand All @@ -105,10 +113,11 @@ export function CalendarRenderer({
return (
<motion.div
key={day.toISOString()}
className={`p-1 border rounded-md cursor-pointer transition-all duration-300 overflow-hidden ${isSelected ? "border-blue-300 dark:border-blue-600" : ""} ${!isCurrentMonth
? "text-gray-400 dark:text-gray-600 bg-gray-100 dark:bg-gray-700"
: ""
} ${getTaskIndicatorStyle(isDarkMode, todoCount, eventCount)} hover:bg-gray-100 dark:hover:bg-gray-700`}
className={`p-1 border rounded-md cursor-pointer transition-all duration-300 overflow-hidden ${isSelected ? "border-blue-300 dark:border-blue-600" : ""} ${
!isCurrentMonth
? "text-gray-400 dark:text-gray-600 bg-gray-100 dark:bg-gray-700"
: ""
} ${getTaskIndicatorStyle(isDarkMode, todoCount, eventCount)} hover:bg-gray-100 dark:hover:bg-gray-700`}
onClick={() => handleDateSelect(day)}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
Expand Down Expand Up @@ -164,4 +173,4 @@ export function CalendarRenderer({
})}
</div>
);
};
}
25 changes: 15 additions & 10 deletions task_yell/src/components/create-event-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ import {
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import {
format,
} from "date-fns";
import { format } from "date-fns";
import { ja } from "date-fns/locale";
import { EventCreator } from "@/components/event-creator";
import { Event, StickyNote } from "@/components/types";
Expand All @@ -20,18 +18,25 @@ type Props = {
setIsEventModalOpen: (isOpen: boolean) => void;
selectedDate: Date;
events: Event[];
addEvent: (newEvent: Event, notification: { date: Date | null; type: "call" | "push" }) => void;
addEvent: (
newEvent: Event,
notification: { date: Date | null; type: "call" | "push" },
) => void;
removedStickyNote: StickyNote | null;
setRemovedStickyNote: (note: StickyNote | null) => void;
draggedStickyNote: StickyNote | null;
};

export function CreateEventDialog({
stickyNotes, setStickyNotes,
isEventModalOpen, setIsEventModalOpen,
stickyNotes,
setStickyNotes,
isEventModalOpen,
setIsEventModalOpen,
selectedDate,
events, addEvent,
removedStickyNote, setRemovedStickyNote,
events,
addEvent,
removedStickyNote,
setRemovedStickyNote,
draggedStickyNote,
}: Props) {
return (
Expand All @@ -57,5 +62,5 @@ export function CreateEventDialog({
/>
</DialogContent>
</Dialog>
)
}
);
}
12 changes: 8 additions & 4 deletions task_yell/src/components/edit-wantodo-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ type Props = {
editingStickyNote: StickyNote | null;
setEditingStickyNote: (stickyNote: StickyNote | null) => void;
updateStickyNote: (stickyNote: StickyNote) => void;
}
};

export function EditWantodoDialog({ editingStickyNote, setEditingStickyNote, updateStickyNote }: Props) {
export function EditWantodoDialog({
editingStickyNote,
setEditingStickyNote,
updateStickyNote,
}: Props) {
return (
<Dialog
open={!!editingStickyNote}
Expand Down Expand Up @@ -50,5 +54,5 @@ export function EditWantodoDialog({ editingStickyNote, setEditingStickyNote, upd
)}
</DialogContent>
</Dialog>
)
}
);
}
31 changes: 22 additions & 9 deletions task_yell/src/components/event-creator.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use client";

import { z } from "zod";
import { DateTimeInput } from "@/components/date-time-input";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
Expand All @@ -20,16 +21,9 @@ import {
Pencil1Icon,
ViewGridIcon,
} from "@radix-ui/react-icons";
import {
format,
getHours,
isSameDay,
} from "date-fns";
import { format, getHours, isSameDay } from "date-fns";
import { ja } from "date-fns/locale";
import {
MapPinIcon,
UserPlusIcon,
} from "lucide-react";
import { MapPinIcon, UserPlusIcon } from "lucide-react";
import { useState } from "react";
import { Event } from "@/components/types";
import { priorityColors } from "./priority-colors";
Expand Down Expand Up @@ -64,6 +58,19 @@ export function EventCreator({
const [notificationType, setNotificationType] = useState<"call" | "push">(
"call",
);
// Zod スキーマの定義
const eventSchema = z.object({
title: z.string().nonempty("タイトルは空白にできません。"),
start: z.date(),
end: z.date(),
description: z.string().optional(),
category: z.string().optional(),
priority: z.string().optional(),
location: z.string().optional(),
invitees: z.array(z.string()).optional(),
isTask: z.boolean(),
isLocked: z.boolean(),
});

const handleSave = () => {
if (targetDate) {
Expand All @@ -80,6 +87,12 @@ export function EventCreator({
isTask,
isLocked,
};
// バリデーションの実行
const result = eventSchema.safeParse(newEvent);
if (!result.success) {
alert(result.error.errors.map((err) => err.message).join("\n"));
return;
}
onSave(newEvent, { date: notificationDate, type: notificationType });
}
};
Expand Down
82 changes: 39 additions & 43 deletions task_yell/src/components/navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,64 +15,60 @@ import { signOut } from "@/firebase/auth";
import { auth, db } from "@/firebase/client-app";
import { subscribeNotification } from "@/lib/push-notification";
import { doc, getDoc, setDoc, updateDoc } from "firebase/firestore";
import {
Menu,
Bell,
Users,
Download,
LogOut,
PhoneCall,
} from "lucide-react";
import { Menu, Bell, Users, Download, LogOut, PhoneCall } from "lucide-react";
import { useRouter } from "next/navigation";
import { useMemo, useState } from "react";

type Props = {
isDarkMode: boolean;
setIsDarkMode: (isDarkMode: boolean) => void;
}
};

export function Navigation({ isDarkMode, setIsDarkMode }: Props) {
const [isOpen, setIsOpen] = useState(false);
const [isNotificationsOpen, setIsNotificationsOpen] = useState(false);
const [notificationsEnabled, setNotificationsEnabled] = useState(false);
const router = useRouter();

const menuItems = useMemo(() => [
{
icon: PhoneCall,
label: "電話通知",
onClick: () => {
return setIsNotificationsOpen(!isNotificationsOpen);
const menuItems = useMemo(
() => [
{
icon: PhoneCall,
label: "電話通知",
onClick: () => {
return setIsNotificationsOpen(!isNotificationsOpen);
},
},
},
{
icon: Bell,
label: "プッシュ通知",
onClick: async () => {
await subscribeNotification();
{
icon: Bell,
label: "プッシュ通知",
onClick: async () => {
await subscribeNotification();
},
},
},
{ icon: Users, label: "友達", onClick: () => console.log("友達") },
{
icon: Download,
label: "インポート",
onClick: () => {
if (auth.currentUser) {
router.push(
`/api/auth/google-cal?userId=${encodeURIComponent(auth.currentUser.uid)}`,
);
}
{ icon: Users, label: "友達", onClick: () => console.log("友達") },
{
icon: Download,
label: "インポート",
onClick: () => {
if (auth.currentUser) {
router.push(
`/api/auth/google-cal?userId=${encodeURIComponent(auth.currentUser.uid)}`,
);
}
},
},
},
{
icon: LogOut,
label: "ログアウト",
onClick: async () => {
await signOut();
router.refresh();
{
icon: LogOut,
label: "ログアウト",
onClick: async () => {
await signOut();
router.refresh();
},
},
},
], [isNotificationsOpen, router]);
],
[isNotificationsOpen, router],
);

return (
<Sheet open={isOpen} onOpenChange={setIsOpen}>
Expand Down Expand Up @@ -157,5 +153,5 @@ export function Navigation({ isDarkMode, setIsDarkMode }: Props) {
</nav>
</SheetContent>
</Sheet>
)
}
);
}
Loading
Loading