From ae61dd0375b03671e68a5756898174e9d86bbd56 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=84=9D=EC=B0=AC=20=EC=9C=A4?= <ysc0731@ajou.ac.kr>
Date: Tue, 3 Dec 2024 01:06:08 +0900
Subject: [PATCH 01/11] =?UTF-8?q?feat:=20=EC=8A=A4=EC=BC=80=EC=A5=B4=20?=
 =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=EB=AA=A8=EB=B0=94=EC=9D=BC=EB=B7=B0?=
 =?UTF-8?q?=20=EA=B0=9C=EB=B0=9C=20(#8)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/pages/Schedule.jsx     |   7 --
 src/pages/SchedulePage.jsx | 210 +++++++++++++++++++++++++++++++++++++
 2 files changed, 210 insertions(+), 7 deletions(-)
 delete mode 100644 src/pages/Schedule.jsx
 create mode 100644 src/pages/SchedulePage.jsx

diff --git a/src/pages/Schedule.jsx b/src/pages/Schedule.jsx
deleted file mode 100644
index 980b0e5..0000000
--- a/src/pages/Schedule.jsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import React from "react";
-
-const Schedule = () => {
-  return <></>;
-};
-
-export default Schedule;
diff --git a/src/pages/SchedulePage.jsx b/src/pages/SchedulePage.jsx
new file mode 100644
index 0000000..12e03af
--- /dev/null
+++ b/src/pages/SchedulePage.jsx
@@ -0,0 +1,210 @@
+import React, { useState, useRef } from "react";
+
+const generateTimeSlots = () => {
+  const timeSlots = [];
+  for (let hour = 0; hour < 24; hour++) {
+    for (let min = 0; min < 60; min += 15) {
+      timeSlots.push(
+        `${hour.toString().padStart(2, "0")}:${min.toString().padStart(2, "0")}`
+      );
+    }
+  }
+  return timeSlots;
+};
+
+const days = ["월", "화", "수", "목", "금", "토", "일"];
+
+const SchedulePage = () => {
+  const timeSlots = generateTimeSlots();
+  const [schedules, setSchedules] = useState([]);
+  const isDragging = useRef(false);
+  const [draggedSlots, setDraggedSlots] = useState([]);
+  const [inputTitle, setInputTitle] = useState("");
+  const [isEditing, setIsEditing] = useState(false);
+  const [editMode, setEditMode] = useState(false);
+
+  const handleMouseDown = (slotIndex) => {
+    if (!editMode) return;
+    isDragging.current = true;
+
+    if (draggedSlots.includes(slotIndex)) {
+      setDraggedSlots((prev) => prev.filter((slot) => slot !== slotIndex));
+      return;
+    }
+
+    setDraggedSlots((prev) => [...new Set([...prev, slotIndex])]);
+
+    const schedule = schedules.find((s) => s.time_idx === slotIndex);
+    if (schedule) {
+      setInputTitle(schedule.title);
+      setIsEditing(true);
+    } else {
+      setInputTitle("");
+      setIsEditing(false);
+    }
+  };
+
+  const handleMouseEnter = (slotIndex) => {
+    if (!editMode || !isDragging.current) return;
+    setDraggedSlots((prev) => [...new Set([...prev, slotIndex])]);
+  };
+
+  const handleMouseUp = () => {
+    isDragging.current = false;
+  };
+
+  const handleMouseLeave = () => {
+    isDragging.current = false;
+  };
+
+  const handleSave = () => {
+    if (!inputTitle.trim()) return;
+
+    const newSchedules = [...schedules];
+    draggedSlots.forEach((slotIndex) => {
+      const existingIndex = newSchedules.findIndex(
+        (s) => s.time_idx === slotIndex
+      );
+      if (existingIndex === -1) {
+        newSchedules.push({
+          id: Date.now(),
+          time_idx: slotIndex,
+          title: inputTitle,
+          is_fixed: false,
+        });
+      } else {
+        newSchedules[existingIndex].title = inputTitle;
+      }
+    });
+
+    setSchedules(newSchedules);
+    setDraggedSlots([]);
+    setInputTitle("");
+    setIsEditing(false);
+  };
+
+  const handleDelete = () => {
+    const newSchedules = schedules.filter(
+      (s) => !draggedSlots.includes(s.time_idx)
+    );
+    setSchedules(newSchedules);
+    setDraggedSlots([]);
+    setInputTitle("");
+    setIsEditing(false);
+  };
+
+  return (
+    <div className="min-h-screen bg-gray-50">
+      {/* Edit Mode Toggle */}
+      <div className="flex items-center justify-between p-4 bg-white shadow">
+        <h1 className="text-lg font-bold mobile:text-base">Schedule</h1>
+        <label className="flex items-center space-x-3">
+          <span className="text-lg font-bold mobile:text-sm">Edit Mode</span>
+          <div
+            className={`relative w-12 h-6 rounded-full cursor-pointer transition-colors ${
+              editMode ? "bg-gradient-pink" : "bg-gray-300"
+            }`}
+            onClick={() => setEditMode((prev) => !prev)}
+          >
+            <div
+              className={`absolute top-0.5 left-0.5 h-5 w-5 rounded-full bg-white transition-transform ${
+                editMode ? "translate-x-6" : ""
+              }`}
+            ></div>
+          </div>
+        </label>
+      </div>
+
+      {/* Sticky Container (Edit Mode가 on일 때만 표시) */}
+      {editMode && (
+        <div className="sticky top-0 flex flex-col gap-2 p-4 bg-white shadow tablet:flex-row tablet:justify-between">
+          <input
+            type="text"
+            value={inputTitle}
+            onChange={(e) => setInputTitle(e.target.value)}
+            placeholder="Enter schedule title"
+            className="flex-1 p-2 border rounded"
+          />
+          <div className="flex space-x-2">
+            <button
+              onClick={handleSave}
+              className="flex-1 px-4 py-2 text-white rounded bg-gradient-pink disabled:opacity-50"
+              disabled={!draggedSlots.length}
+            >
+              {isEditing ? "Update" : "Save"}
+            </button>
+            <button
+              onClick={handleDelete}
+              className="flex-1 px-4 py-2 text-white rounded bg-gradient-purple disabled:opacity-50"
+              disabled={!draggedSlots.length}
+            >
+              Delete
+            </button>
+          </div>
+        </div>
+      )}
+
+      {/* Schedule Grid */}
+      <div className="p-4">
+        <div className="overflow-auto scrollbar-hide">
+          <div className="tablet:w-[960px] tablet:min-w-[800px] grid grid-cols-[64px,repeat(7,1fr)] gap-2">
+            {/* Header */}
+            <div className="min-w-[54px] p-2 font-bold text-center bg-gray-200 select-none">
+              Time
+            </div>
+            {days.map((day) => (
+              <div
+                key={day}
+                className="p-2 font-bold text-center bg-gray-200 select-none"
+              >
+                {day}
+              </div>
+            ))}
+
+            {/* Time Slots */}
+            {timeSlots.map((time, rowIndex) => (
+              <React.Fragment key={rowIndex}>
+                {/* Time Column */}
+                <div className="min-w-[54px] p-2 text-sm font-bold text-center bg-gray-100 select-none">
+                  {time}
+                </div>
+                {days.map((_, colIndex) => {
+                  const slotIndex = colIndex * timeSlots.length + rowIndex;
+                  const isSelected = draggedSlots.includes(slotIndex);
+                  const schedule = schedules.find(
+                    (s) => s.time_idx === slotIndex
+                  );
+
+                  return (
+                    <div
+                      key={slotIndex}
+                      className={`p-2 border rounded cursor-pointer ${
+                        editMode
+                          ? isSelected
+                            ? "bg-tertiary-300"
+                            : schedule
+                            ? "bg-primary-500 text-white"
+                            : "bg-white"
+                          : schedule
+                          ? "bg-primary-500 text-white"
+                          : "bg-gray-50"
+                      }`}
+                      onMouseDown={() => handleMouseDown(slotIndex)}
+                      onMouseEnter={() => handleMouseEnter(slotIndex)}
+                      onMouseUp={handleMouseUp}
+                      onMouseLeave={handleMouseLeave}
+                    >
+                      {schedule && !isSelected ? schedule.title : ""}
+                    </div>
+                  );
+                })}
+              </React.Fragment>
+            ))}
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default SchedulePage;
-- 
GitLab


From 6bafaeddff21d974c002dae6b30b3cfe39a66320 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=84=9D=EC=B0=AC=20=EC=9C=A4?= <ysc0731@ajou.ac.kr>
Date: Thu, 5 Dec 2024 16:58:39 +0900
Subject: [PATCH 02/11] =?UTF-8?q?feat:=20schedul=20api=20=ED=98=B8?=
 =?UTF-8?q?=EC=B6=9C=20=EA=B4=80=EB=A6=AC=20=ED=95=A8=EC=88=98=EC=B6=94?=
 =?UTF-8?q?=EA=B0=80=20(#8)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .gitignore          |   1 +
 src/api/schedule.js | 157 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 158 insertions(+)
 create mode 100644 src/api/schedule.js

diff --git a/.gitignore b/.gitignore
index 4d29575..8692cf6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@
 
 # misc
 .DS_Store
+.env
 .env.local
 .env.development.local
 .env.test.local
diff --git a/src/api/schedule.js b/src/api/schedule.js
new file mode 100644
index 0000000..bb36ad4
--- /dev/null
+++ b/src/api/schedule.js
@@ -0,0 +1,157 @@
+// api.js
+const baseURL = process.env.REACT_APP_BACKEND_BASE_URL;
+
+// Fetch all schedules
+export const fetchAllSchedules = async () => {
+  try {
+    const response = await fetch(`${baseURL}/api/schedule/all`, {
+      method: "GET",
+      credentials: "include", // Include credentials for session-based authentication
+      headers: {
+        "Content-Type": "application/json",
+      },
+    });
+
+    if (!response.ok) {
+      throw new Error(`Error: ${response.status}`);
+    }
+
+    const result = await response.json();
+
+    if (!result.success) {
+      throw new Error("Failed to fetch schedules.");
+    }
+
+    return result.data.schedules;
+  } catch (error) {
+    console.error("Error fetching schedules:", error);
+    throw error;
+  }
+};
+
+// Fetch schedule by time index
+export const fetchScheduleByTimeIndex = async (timeIdx) => {
+  try {
+    const response = await fetch(`${baseURL}/api/schedule/${timeIdx}`, {
+      method: "GET",
+      credentials: "include", // Include credentials for session-based authentication
+      headers: {
+        "Content-Type": "application/json",
+      },
+    });
+
+    if (!response.ok) {
+      if (response.status === 404) {
+        const error = await response.json();
+        throw new Error(error.error.message || "Schedule not found.");
+      }
+      throw new Error(`Error: ${response.status}`);
+    }
+
+    const result = await response.json();
+
+    if (!result.success) {
+      throw new Error("Failed to fetch schedule.");
+    }
+
+    return result.data.schedule;
+  } catch (error) {
+    console.error(`Error fetching schedule with timeIdx ${timeIdx}:`, error);
+    throw error;
+  }
+};
+
+// Create a new schedule
+export const createSchedule = async (scheduleData) => {
+  try {
+    const response = await fetch(`${baseURL}/api/schedule`, {
+      method: "POST",
+      credentials: "include", // Include credentials for session-based authentication
+      headers: {
+        "Content-Type": "application/json",
+      },
+      body: JSON.stringify(scheduleData),
+    });
+
+    if (!response.ok) {
+      if (response.status === 400) {
+        const error = await response.json();
+        throw new Error(error.error.message || "Failed to create schedule.");
+      }
+      throw new Error(`Error: ${response.status}`);
+    }
+
+    const result = await response.json();
+
+    if (!result.success) {
+      throw new Error("Failed to create schedule.");
+    }
+
+    return result.data.schedule;
+  } catch (error) {
+    console.error("Error creating schedule:", error);
+    throw error;
+  }
+};
+
+// Update an existing schedule
+export const updateSchedule = async (scheduleData) => {
+  try {
+    const response = await fetch(`${baseURL}/api/schedule`, {
+      method: "PUT",
+      credentials: "include", // Include credentials for session-based authentication
+      headers: {
+        "Content-Type": "application/json",
+      },
+      body: JSON.stringify(scheduleData),
+    });
+
+    if (!response.ok) {
+      throw new Error(`Error: ${response.status}`);
+    }
+
+    const result = await response.json();
+
+    if (!result.success) {
+      throw new Error("Failed to update schedule.");
+    }
+
+    return result.data.schedule;
+  } catch (error) {
+    console.error("Error updating schedule:", error);
+    throw error;
+  }
+};
+
+// Delete a schedule
+export const deleteSchedule = async (title) => {
+  try {
+    const response = await fetch(`${baseURL}/api/schedule`, {
+      method: "DELETE",
+      credentials: "include", // Include credentials for session-based authentication
+      headers: {
+        "Content-Type": "application/json",
+      },
+      body: JSON.stringify({ title }),
+    });
+
+    if (!response.ok) {
+      if (response.status === 404) {
+        const error = await response.json();
+        throw new Error(error.error.message || "Schedule not found.");
+      }
+      throw new Error(`Error: ${response.status}`);
+    }
+
+    const result = await response.json();
+
+    if (!result.success) {
+      throw new Error("Failed to delete schedule.");
+    }
+
+    return result.data;
+  } catch (error) {
+    console.error("Error deleting schedule:", error);
+    throw error;
+  }
+};
-- 
GitLab


From f45e8d89909dcaab117eab92af2948c70f2c489b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=84=9D=EC=B0=AC=20=EC=9C=A4?= <ysc0731@ajou.ac.kr>
Date: Thu, 5 Dec 2024 16:59:37 +0900
Subject: [PATCH 03/11] =?UTF-8?q?rename:=20timetable=20=ED=8C=8C=EC=9D=BC?=
 =?UTF-8?q?=EB=AA=85=20=EC=88=98=EC=A0=95=20(#8)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/App.js                  | 4 ++--
 src/pages/SchedulePage.jsx  | 2 +-
 src/pages/TimeTablePage.jsx | 7 -------
 3 files changed, 3 insertions(+), 10 deletions(-)
 delete mode 100644 src/pages/TimeTablePage.jsx

diff --git a/src/App.js b/src/App.js
index 689e5d3..43a9c0d 100644
--- a/src/App.js
+++ b/src/App.js
@@ -4,13 +4,13 @@ import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
 import LoginPage from "./pages/LoginPage";
 import SignupPage from "./pages/SignUpPage";
 import HomePage from "./pages/HomePage";
-import TimeTablePage from "./pages/TimeTablePage";
 import ChattingListPage from "./pages/Chatting/ChattingListPage";
 import MyPage from "./pages/Mypage";
 import HeaderNav from "./components/layout/HeaderNav";
 import Footer from "./components/layout/Footer";
 import BodyLayout from "./components/layout/BodyLayout";
 import HeaderLogoBar from "./components/layout/HeaderLogoBar";
+import SchedulePage from "./pages/SchedulePage";
 
 const App = () => {
   return (
@@ -21,7 +21,7 @@ const App = () => {
         <BodyLayout>
           <Routes>
             <Route path="/" element={<HomePage />} />
-            <Route path="/timetable" element={<TimeTablePage />} />
+            <Route path="/timetable" element={<SchedulePage />} />
             <Route path="/chattinglist" element={<ChattingListPage />} />
             <Route path="/mypage" element={<MyPage />} />
             <Route path="/login" element={<LoginPage />} />
diff --git a/src/pages/SchedulePage.jsx b/src/pages/SchedulePage.jsx
index 12e03af..ec88ddf 100644
--- a/src/pages/SchedulePage.jsx
+++ b/src/pages/SchedulePage.jsx
@@ -147,7 +147,7 @@ const SchedulePage = () => {
       {/* Schedule Grid */}
       <div className="p-4">
         <div className="overflow-auto scrollbar-hide">
-          <div className="tablet:w-[960px] tablet:min-w-[800px] grid grid-cols-[64px,repeat(7,1fr)] gap-2">
+          <div className="w-[100vw] tablet:w-[960px] grid grid-cols-[64px,repeat(7,1fr)] gap-2">
             {/* Header */}
             <div className="min-w-[54px] p-2 font-bold text-center bg-gray-200 select-none">
               Time
diff --git a/src/pages/TimeTablePage.jsx b/src/pages/TimeTablePage.jsx
deleted file mode 100644
index 059584d..0000000
--- a/src/pages/TimeTablePage.jsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import React from "react";
-
-const TimeTablePage = () => {
-  return <></>;
-};
-
-export default TimeTablePage;
-- 
GitLab


From a6aec49bfc383fbbc02541048b810f39fd031ff1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=84=9D=EC=B0=AC=20=EC=9C=A4?= <ysc0731@ajou.ac.kr>
Date: Thu, 5 Dec 2024 17:51:38 +0900
Subject: [PATCH 04/11] =?UTF-8?q?feat:=20schedule=20=EC=B6=94=EA=B0=80,=20?=
 =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=ED=99=95=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=20?=
 =?UTF-8?q?=EA=B0=9C=EB=B0=9C=20(#8)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/pages/SchedulePage.jsx | 288 +++++++++++++++++++++----------------
 1 file changed, 168 insertions(+), 120 deletions(-)

diff --git a/src/pages/SchedulePage.jsx b/src/pages/SchedulePage.jsx
index ec88ddf..2d85714 100644
--- a/src/pages/SchedulePage.jsx
+++ b/src/pages/SchedulePage.jsx
@@ -1,4 +1,5 @@
-import React, { useState, useRef } from "react";
+import React, { useEffect, useState } from "react";
+// import { createSchedule } from "./api"; // API 호출 주석 처리
 
 const generateTimeSlots = () => {
   const timeSlots = [];
@@ -14,132 +15,186 @@ const generateTimeSlots = () => {
 
 const days = ["월", "화", "수", "목", "금", "토", "일"];
 
+const dummySchedules = [
+  {
+    id: 1,
+    user_id: 1,
+    title: "알고리즘 스터디",
+    is_fixed: true,
+    time_indices: [36, 37, 38, 39],
+    createdAt: "2024-12-02T09:52:00.000Z",
+    updatedAt: "2024-12-02T09:52:00.000Z",
+  },
+  {
+    id: 5,
+    user_id: 1,
+    title: "웹시설 팀플",
+    is_fixed: true,
+    time_indices: [165, 166, 167, 255, 256, 257],
+    createdAt: "2024-12-02T09:54:53.000Z",
+    updatedAt: "2024-12-02T09:54:53.000Z",
+  },
+];
+
 const SchedulePage = () => {
   const timeSlots = generateTimeSlots();
   const [schedules, setSchedules] = useState([]);
-  const isDragging = useRef(false);
-  const [draggedSlots, setDraggedSlots] = useState([]);
-  const [inputTitle, setInputTitle] = useState("");
-  const [isEditing, setIsEditing] = useState(false);
-  const [editMode, setEditMode] = useState(false);
-
-  const handleMouseDown = (slotIndex) => {
-    if (!editMode) return;
-    isDragging.current = true;
-
-    if (draggedSlots.includes(slotIndex)) {
-      setDraggedSlots((prev) => prev.filter((slot) => slot !== slotIndex));
-      return;
-    }
+  const [isEditMode, setIsEditMode] = useState(false);
+  const [selectedSchedule, setSelectedSchedule] = useState(null);
+  const [selectedSlots, setSelectedSlots] = useState([]);
+  const [newTitle, setNewTitle] = useState("");
+  const [isFixed, setIsFixed] = useState(true);
 
-    setDraggedSlots((prev) => [...new Set([...prev, slotIndex])]);
+  useEffect(() => {
+    setSchedules(dummySchedules);
+  }, []);
 
-    const schedule = schedules.find((s) => s.time_idx === slotIndex);
-    if (schedule) {
-      setInputTitle(schedule.title);
-      setIsEditing(true);
-    } else {
-      setInputTitle("");
-      setIsEditing(false);
-    }
-  };
+  const handleSlotClick = (timeIdx) => {
+    if (!isEditMode) return;
 
-  const handleMouseEnter = (slotIndex) => {
-    if (!editMode || !isDragging.current) return;
-    setDraggedSlots((prev) => [...new Set([...prev, slotIndex])]);
-  };
+    const slotInSchedule = schedules.find((s) =>
+      s.time_indices.includes(timeIdx)
+    );
 
-  const handleMouseUp = () => {
-    isDragging.current = false;
-  };
+    if (slotInSchedule) {
+      if (selectedSlots.length === 0) {
+        setSelectedSchedule(slotInSchedule);
+      }
+      return;
+    }
 
-  const handleMouseLeave = () => {
-    isDragging.current = false;
+    // Toggle slot selection for new schedule creation
+    if (selectedSlots.includes(timeIdx)) {
+      setSelectedSlots((prev) => prev.filter((idx) => idx !== timeIdx));
+    } else {
+      setSelectedSlots((prev) => [...prev, timeIdx]);
+    }
   };
 
-  const handleSave = () => {
-    if (!inputTitle.trim()) return;
+  const handleCreateSchedule = async () => {
+    if (!newTitle.trim() || selectedSlots.length === 0) {
+      alert("Title must not be empty and at least one slot must be selected.");
+      return;
+    }
 
-    const newSchedules = [...schedules];
-    draggedSlots.forEach((slotIndex) => {
-      const existingIndex = newSchedules.findIndex(
-        (s) => s.time_idx === slotIndex
-      );
-      if (existingIndex === -1) {
-        newSchedules.push({
-          id: Date.now(),
-          time_idx: slotIndex,
-          title: inputTitle,
-          is_fixed: false,
-        });
-      } else {
-        newSchedules[existingIndex].title = inputTitle;
-      }
-    });
+    const newSchedule = {
+      title: newTitle,
+      is_fixed: isFixed,
+      time_indices: selectedSlots,
+    };
 
-    setSchedules(newSchedules);
-    setDraggedSlots([]);
-    setInputTitle("");
-    setIsEditing(false);
-  };
+    try {
+      // API 호출 준비가 되었을 때 사용:
+      // await createSchedule(newSchedule);
 
-  const handleDelete = () => {
-    const newSchedules = schedules.filter(
-      (s) => !draggedSlots.includes(s.time_idx)
-    );
-    setSchedules(newSchedules);
-    setDraggedSlots([]);
-    setInputTitle("");
-    setIsEditing(false);
+      // 임시로 더미 데이터에 추가
+      setSchedules((prev) => [
+        ...prev,
+        { ...newSchedule, id: Date.now(), user_id: 1 },
+      ]);
+      setSelectedSlots([]);
+      setNewTitle("");
+      setIsFixed(true);
+      alert("Schedule created successfully!");
+    } catch (error) {
+      console.error("Failed to create schedule:", error);
+    }
   };
 
   return (
-    <div className="min-h-screen bg-gray-50">
-      {/* Edit Mode Toggle */}
+    <div className="min-h-screen bg-grayscale-50">
+      {/* Toggle View/Edit Mode */}
       <div className="flex items-center justify-between p-4 bg-white shadow">
-        <h1 className="text-lg font-bold mobile:text-base">Schedule</h1>
-        <label className="flex items-center space-x-3">
-          <span className="text-lg font-bold mobile:text-sm">Edit Mode</span>
+        <h1 className="heading-1 text-primary-500">Schedule</h1>
+        <label className="flex items-center space-x-3 cursor-pointer">
+          <span className="title-1 text-secondary-500">Edit Mode</span>
           <div
-            className={`relative w-12 h-6 rounded-full cursor-pointer transition-colors ${
-              editMode ? "bg-gradient-pink" : "bg-gray-300"
+            className={`relative w-12 h-6 rounded-full transition-colors ${
+              isEditMode ? "bg-primary-500" : "bg-grayscale-300"
             }`}
-            onClick={() => setEditMode((prev) => !prev)}
+            onClick={() => {
+              setIsEditMode((prev) => !prev);
+              setSelectedSlots([]);
+              setSelectedSchedule(null);
+            }}
           >
             <div
               className={`absolute top-0.5 left-0.5 h-5 w-5 rounded-full bg-white transition-transform ${
-                editMode ? "translate-x-6" : ""
+                isEditMode ? "translate-x-6" : ""
               }`}
             ></div>
           </div>
         </label>
       </div>
 
-      {/* Sticky Container (Edit Mode가 on일 때만 표시) */}
-      {editMode && (
-        <div className="sticky top-0 flex flex-col gap-2 p-4 bg-white shadow tablet:flex-row tablet:justify-between">
-          <input
-            type="text"
-            value={inputTitle}
-            onChange={(e) => setInputTitle(e.target.value)}
-            placeholder="Enter schedule title"
-            className="flex-1 p-2 border rounded"
-          />
-          <div className="flex space-x-2">
-            <button
-              onClick={handleSave}
-              className="flex-1 px-4 py-2 text-white rounded bg-gradient-pink disabled:opacity-50"
-              disabled={!draggedSlots.length}
-            >
-              {isEditing ? "Update" : "Save"}
-            </button>
-            <button
-              onClick={handleDelete}
-              className="flex-1 px-4 py-2 text-white rounded bg-gradient-purple disabled:opacity-50"
-              disabled={!draggedSlots.length}
-            >
-              Delete
-            </button>
+      {/* Sticky Container in Edit Mode */}
+      {isEditMode && (
+        <div className="fixed bottom-0 left-0 right-0 flex items-center justify-center w-screen">
+          <div
+            className={`transform transition-transform w-full max-w-[760px] tablet:rounded-2xl bg-primary-100 p-6 text-center shadow-lg`}
+          >
+            {selectedSlots.length === 0 && selectedSchedule ? (
+              <>
+                <h3 className="mb-2 heading-2 text-primary-500">
+                  Schedule Details
+                </h3>
+                <p className="mb-1 body-1">
+                  <strong>Title:</strong> {selectedSchedule.title}
+                </p>
+                <p className="mb-1 body-1">
+                  <strong>Fixed:</strong>{" "}
+                  {selectedSchedule.is_fixed ? "Yes" : "No"}
+                </p>
+                <p className="body-1">
+                  <strong>Time Indices:</strong>{" "}
+                  {selectedSchedule.time_indices.join(", ")}
+                </p>
+              </>
+            ) : (
+              <>
+                <h3 className="mb-4 heading-2 text-primary-500">
+                  Create New Schedule
+                </h3>
+                <input
+                  type="text"
+                  value={newTitle}
+                  onChange={(e) => setNewTitle(e.target.value)}
+                  placeholder="Enter title"
+                  className="w-full p-2 mb-4 border rounded shadow-input-box"
+                />
+                <div className="flex items-center justify-center mb-4 space-x-4">
+                  <label className="flex items-center space-x-2">
+                    <input
+                      type="radio"
+                      name="is_fixed"
+                      value={true}
+                      checked={isFixed === true}
+                      onChange={() => setIsFixed(true)}
+                    />
+                    <span className="body-1">Fixed</span>
+                  </label>
+                  <label className="flex items-center space-x-2">
+                    <input
+                      type="radio"
+                      name="is_fixed"
+                      value={false}
+                      checked={isFixed === false}
+                      onChange={() => setIsFixed(false)}
+                    />
+                    <span className="body-1">Flexible</span>
+                  </label>
+                </div>
+                <p className="mb-4 body-1">
+                  Selected Slots: {selectedSlots.join(", ")}
+                </p>
+                <button
+                  onClick={handleCreateSchedule}
+                  className="px-4 py-2 font-bold text-white rounded bg-gradient-pink"
+                >
+                  Add Schedule
+                </button>
+              </>
+            )}
           </div>
         </div>
       )}
@@ -149,13 +204,13 @@ const SchedulePage = () => {
         <div className="overflow-auto scrollbar-hide">
           <div className="w-[100vw] tablet:w-[960px] grid grid-cols-[64px,repeat(7,1fr)] gap-2">
             {/* Header */}
-            <div className="min-w-[54px] p-2 font-bold text-center bg-gray-200 select-none">
+            <div className="min-w-[54px] p-2 font-bold text-center bg-grayscale-200 select-none">
               Time
             </div>
             {days.map((day) => (
               <div
                 key={day}
-                className="p-2 font-bold text-center bg-gray-200 select-none"
+                className="p-2 font-bold text-center select-none bg-grayscale-200"
               >
                 {day}
               </div>
@@ -165,36 +220,29 @@ const SchedulePage = () => {
             {timeSlots.map((time, rowIndex) => (
               <React.Fragment key={rowIndex}>
                 {/* Time Column */}
-                <div className="min-w-[54px] p-2 text-sm font-bold text-center bg-gray-100 select-none">
+                <div className="min-w-[54px] p-2 font-bold text-center bg-grayscale-100 select-none">
                   {time}
                 </div>
                 {days.map((_, colIndex) => {
                   const slotIndex = colIndex * timeSlots.length + rowIndex;
-                  const isSelected = draggedSlots.includes(slotIndex);
-                  const schedule = schedules.find(
-                    (s) => s.time_idx === slotIndex
+                  const isSelected = selectedSlots.includes(slotIndex);
+                  const schedule = schedules.find((s) =>
+                    s.time_indices.includes(slotIndex)
                   );
 
                   return (
                     <div
                       key={slotIndex}
-                      className={`p-2 border rounded cursor-pointer ${
-                        editMode
-                          ? isSelected
-                            ? "bg-tertiary-300"
-                            : schedule
-                            ? "bg-primary-500 text-white"
-                            : "bg-white"
-                          : schedule
-                          ? "bg-primary-500 text-white"
-                          : "bg-gray-50"
+                      className={`p-2 border rounded ${
+                        schedule
+                          ? "bg-primary-300 text-white cursor-not-allowed"
+                          : isSelected
+                          ? "bg-primary-100 border-primary-300"
+                          : "bg-grayscale-50 cursor-pointer"
                       }`}
-                      onMouseDown={() => handleMouseDown(slotIndex)}
-                      onMouseEnter={() => handleMouseEnter(slotIndex)}
-                      onMouseUp={handleMouseUp}
-                      onMouseLeave={handleMouseLeave}
+                      onClick={() => handleSlotClick(slotIndex)}
                     >
-                      {schedule && !isSelected ? schedule.title : ""}
+                      {schedule ? schedule.title : ""}
                     </div>
                   );
                 })}
-- 
GitLab


From 1709d38c6dbde71fe2b4f03b252baab211c5ddef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=84=9D=EC=B0=AC=20=EC=9C=A4?= <ysc0731@ajou.ac.kr>
Date: Thu, 5 Dec 2024 17:57:48 +0900
Subject: [PATCH 05/11] =?UTF-8?q?feat:=20=EC=8A=A4=EC=BC=80=EC=A4=84=20?=
 =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EB=A1=9C=EC=A7=81=20=EA=B0=9C=EB=B0=9C=20?=
 =?UTF-8?q?(#8)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/pages/SchedulePage.jsx | 70 ++++++++++++++++++++++++--------------
 1 file changed, 45 insertions(+), 25 deletions(-)

diff --git a/src/pages/SchedulePage.jsx b/src/pages/SchedulePage.jsx
index 2d85714..87132e3 100644
--- a/src/pages/SchedulePage.jsx
+++ b/src/pages/SchedulePage.jsx
@@ -1,5 +1,5 @@
 import React, { useEffect, useState } from "react";
-// import { createSchedule } from "./api"; // API 호출 주석 처리
+// import { createSchedule, deleteSchedule, fetchAllSchedules } from "./api"; // API 호출 주석 유지
 
 const generateTimeSlots = () => {
   const timeSlots = [];
@@ -46,6 +46,18 @@ const SchedulePage = () => {
   const [isFixed, setIsFixed] = useState(true);
 
   useEffect(() => {
+    // const initializeSchedules = async () => {
+    //   try {
+    //     const data = await fetchAllSchedules();
+    //     setSchedules(data);
+    //   } catch (error) {
+    //     console.error("Failed to load schedules", error);
+    //   }
+    // };
+
+    // initializeSchedules();
+
+    // 현재는 더미 데이터로 초기화
     setSchedules(dummySchedules);
   }, []);
 
@@ -63,7 +75,6 @@ const SchedulePage = () => {
       return;
     }
 
-    // Toggle slot selection for new schedule creation
     if (selectedSlots.includes(timeIdx)) {
       setSelectedSlots((prev) => prev.filter((idx) => idx !== timeIdx));
     } else {
@@ -71,33 +82,26 @@ const SchedulePage = () => {
     }
   };
 
-  const handleCreateSchedule = async () => {
-    if (!newTitle.trim() || selectedSlots.length === 0) {
-      alert("Title must not be empty and at least one slot must be selected.");
-      return;
-    }
-
-    const newSchedule = {
-      title: newTitle,
-      is_fixed: isFixed,
-      time_indices: selectedSlots,
-    };
+  const handleDeleteSchedule = async () => {
+    if (!selectedSchedule) return;
 
     try {
+      const body = { title: selectedSchedule.title };
+
       // API 호출 준비가 되었을 때 사용:
-      // await createSchedule(newSchedule);
+      // await deleteSchedule(body);
+
+      // const updatedSchedules = await fetchAllSchedules();
+      // setSchedules(updatedSchedules);
 
-      // 임시로 더미 데이터에 추가
-      setSchedules((prev) => [
-        ...prev,
-        { ...newSchedule, id: Date.now(), user_id: 1 },
-      ]);
-      setSelectedSlots([]);
-      setNewTitle("");
-      setIsFixed(true);
-      alert("Schedule created successfully!");
+      // 임시로 삭제 처리
+      setSchedules((prev) =>
+        prev.filter((s) => s.title !== selectedSchedule.title)
+      );
+      setSelectedSchedule(null);
+      alert("Schedule deleted successfully!");
     } catch (error) {
-      console.error("Failed to create schedule:", error);
+      console.error("Failed to delete schedule:", error);
     }
   };
 
@@ -149,6 +153,22 @@ const SchedulePage = () => {
                   <strong>Time Indices:</strong>{" "}
                   {selectedSchedule.time_indices.join(", ")}
                 </p>
+                <div className="flex justify-center mt-4 space-x-4">
+                  <button
+                    className="px-4 py-2 font-bold text-white rounded bg-gradient-purple"
+                    onClick={() =>
+                      alert("Edit functionality not implemented yet")
+                    }
+                  >
+                    Edit
+                  </button>
+                  <button
+                    className="px-4 py-2 font-bold text-white rounded bg-gradient-pink"
+                    onClick={handleDeleteSchedule}
+                  >
+                    Delete
+                  </button>
+                </div>
               </>
             ) : (
               <>
@@ -188,8 +208,8 @@ const SchedulePage = () => {
                   Selected Slots: {selectedSlots.join(", ")}
                 </p>
                 <button
-                  onClick={handleCreateSchedule}
                   className="px-4 py-2 font-bold text-white rounded bg-gradient-pink"
+                  onClick={() => alert("Schedule created")}
                 >
                   Add Schedule
                 </button>
-- 
GitLab


From 0d82ce722c1ea82c8bf163e3c903a4f5446580c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=84=9D=EC=B0=AC=20=EC=9C=A4?= <ysc0731@ajou.ac.kr>
Date: Fri, 6 Dec 2024 00:27:49 +0900
Subject: [PATCH 06/11] =?UTF-8?q?feat:=20=EC=8A=A4=EC=BC=80=EC=A5=B4=20?=
 =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81=20=EB=B0=8F=20=EB=94=94?=
 =?UTF-8?q?=EC=9E=90=EC=9D=B8=20=EC=88=98=EC=A0=95=20(#8)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/pages/SchedulePage.jsx | 66 ++++++++++++++++++++++++++++++--------
 1 file changed, 53 insertions(+), 13 deletions(-)

diff --git a/src/pages/SchedulePage.jsx b/src/pages/SchedulePage.jsx
index 87132e3..8a9f684 100644
--- a/src/pages/SchedulePage.jsx
+++ b/src/pages/SchedulePage.jsx
@@ -1,4 +1,5 @@
 import React, { useEffect, useState } from "react";
+import Label from "../components/Label";
 // import { createSchedule, deleteSchedule, fetchAllSchedules } from "./api"; // API 호출 주석 유지
 
 const generateTimeSlots = () => {
@@ -82,6 +83,36 @@ const SchedulePage = () => {
     }
   };
 
+  const handleCreateSchedule = async () => {
+    try {
+      const scheduleData = {
+        title: newTitle,
+        is_fixed: isFixed,
+        time_indices: selectedSlots,
+      };
+
+      // API 호출 부분 (주석 처리)
+      // const newSchedule = await createSchedule(scheduleData);
+
+      // 임시로 더미 데이터에 추가
+      const newSchedule = {
+        ...scheduleData,
+        id: Date.now(),
+        createdAt: new Date().toISOString(),
+        updatedAt: new Date().toISOString(),
+      };
+
+      setSchedules((prev) => [...prev, newSchedule]);
+      setSelectedSlots([]);
+      setNewTitle("");
+      setIsFixed(true);
+      alert("Schedule created successfully!");
+    } catch (error) {
+      console.error("Failed to create schedule:", error);
+      alert("Failed to create schedule.");
+    }
+  };
+
   const handleDeleteSchedule = async () => {
     if (!selectedSchedule) return;
 
@@ -133,9 +164,9 @@ const SchedulePage = () => {
 
       {/* Sticky Container in Edit Mode */}
       {isEditMode && (
-        <div className="fixed bottom-0 left-0 right-0 flex items-center justify-center w-screen">
+        <div className="fixed bottom-0 right-0 flex items-center justify-center w-screen">
           <div
-            className={`transform transition-transform w-full max-w-[760px] tablet:rounded-2xl bg-primary-100 p-6 text-center shadow-lg`}
+            className={`transform transition-transform w-full max-w-[768px] tablet:rounded-2xl bg-primary-100 p-6 text-center shadow-lg`}
           >
             {selectedSlots.length === 0 && selectedSchedule ? (
               <>
@@ -147,12 +178,16 @@ const SchedulePage = () => {
                 </p>
                 <p className="mb-1 body-1">
                   <strong>Fixed:</strong>{" "}
-                  {selectedSchedule.is_fixed ? "Yes" : "No"}
-                </p>
-                <p className="body-1">
-                  <strong>Time Indices:</strong>{" "}
-                  {selectedSchedule.time_indices.join(", ")}
+                  {selectedSchedule.is_fixed ? "고정" : "유동"}
                 </p>
+                <div className="mb-4 body-1">
+                  <span>Time Indices:</span>
+                  {selectedSchedule.time_indices.map((time_idx) => (
+                    <Label key={time_idx} theme="indigo" size="sm">
+                      {time_idx}
+                    </Label>
+                  ))}
+                </div>
                 <div className="flex justify-center mt-4 space-x-4">
                   <button
                     className="px-4 py-2 font-bold text-white rounded bg-gradient-purple"
@@ -191,7 +226,7 @@ const SchedulePage = () => {
                       checked={isFixed === true}
                       onChange={() => setIsFixed(true)}
                     />
-                    <span className="body-1">Fixed</span>
+                    <span className="body-1">고정</span>
                   </label>
                   <label className="flex items-center space-x-2">
                     <input
@@ -201,15 +236,20 @@ const SchedulePage = () => {
                       checked={isFixed === false}
                       onChange={() => setIsFixed(false)}
                     />
-                    <span className="body-1">Flexible</span>
+                    <span className="body-1">유동</span>
                   </label>
                 </div>
-                <p className="mb-4 body-1">
-                  Selected Slots: {selectedSlots.join(", ")}
-                </p>
+                <div className="mb-4 body-1">
+                  <span>Selected Slots:</span>
+                  {selectedSlots.map((time_idx) => (
+                    <Label key={time_idx} theme="indigo" size="sm">
+                      {time_idx}
+                    </Label>
+                  ))}
+                </div>
                 <button
                   className="px-4 py-2 font-bold text-white rounded bg-gradient-pink"
-                  onClick={() => alert("Schedule created")}
+                  onClick={() => handleCreateSchedule()}
                 >
                   Add Schedule
                 </button>
-- 
GitLab


From 08c27311e7be908eb08567db6f314e0a1149855f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=84=9D=EC=B0=AC=20=EC=9C=A4?= <ysc0731@ajou.ac.kr>
Date: Fri, 6 Dec 2024 00:58:02 +0900
Subject: [PATCH 07/11] =?UTF-8?q?feat:=20=EC=8A=A4=EC=BC=80=EC=A4=84=20?=
 =?UTF-8?q?=EC=88=98=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EB=B0=9C=20?=
 =?UTF-8?q?(#8)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/pages/SchedulePage.jsx | 80 +++++++++++++++++++++++++++++++++-----
 1 file changed, 70 insertions(+), 10 deletions(-)

diff --git a/src/pages/SchedulePage.jsx b/src/pages/SchedulePage.jsx
index 8a9f684..b796046 100644
--- a/src/pages/SchedulePage.jsx
+++ b/src/pages/SchedulePage.jsx
@@ -41,6 +41,7 @@ const SchedulePage = () => {
   const timeSlots = generateTimeSlots();
   const [schedules, setSchedules] = useState([]);
   const [isEditMode, setIsEditMode] = useState(false);
+  const [isUpdateMode, setIsUpdateMode] = useState(false);
   const [selectedSchedule, setSelectedSchedule] = useState(null);
   const [selectedSlots, setSelectedSlots] = useState([]);
   const [newTitle, setNewTitle] = useState("");
@@ -62,7 +63,7 @@ const SchedulePage = () => {
     setSchedules(dummySchedules);
   }, []);
 
-  const handleSlotClick = (timeIdx) => {
+  const handleSlotClick = async (timeIdx) => {
     if (!isEditMode) return;
 
     const slotInSchedule = schedules.find((s) =>
@@ -81,6 +82,58 @@ const SchedulePage = () => {
     } else {
       setSelectedSlots((prev) => [...prev, timeIdx]);
     }
+
+    // API 호출 준비가 되었을 때 사용:
+    // try {
+    //   const response = await fetchScheduleByTimeIndex(timeIdx);
+    //   if (response && response.data && response.data.schedule) {
+    //     setSelectedSchedule(response.data.schedule); // API로 가져온 스케줄 설정
+    //   } else {
+    //     console.error("No schedule found for time index:", timeIdx);
+    //   }
+    // } catch (error) {
+    //   console.error("Failed to fetch schedule for time index:", timeIdx, error);
+    // }
+  };
+
+  const handleEditSchedule = () => {
+    setIsUpdateMode(true);
+    setSchedules((prev) =>
+      prev.filter((s) => s.title !== selectedSchedule.title)
+    );
+    setSelectedSlots(selectedSchedule.time_indices);
+    setNewTitle(selectedSchedule.title);
+    setIsFixed(selectedSchedule.is_fixed);
+  };
+
+  const handleUpdateSchedule = async () => {
+    try {
+      const scheduleData = {
+        originalTitle: selectedSchedule.title,
+        title: newTitle,
+        is_fixed: isFixed,
+        time_indices: selectedSlots,
+      };
+      // API 호출 부분 (주석 처리)
+      // const newSchedule = await updateSchedule(scheduleData);
+      // 임시로 더미 데이터에 추가
+      const newSchedule = {
+        ...scheduleData,
+        id: Date.now(),
+        createdAt: new Date().toISOString(),
+        updatedAt: new Date().toISOString(),
+      };
+
+      setSchedules((prev) => [...prev, newSchedule]);
+      setSelectedSchedule(newSchedule);
+      setSelectedSlots([]);
+      setNewTitle("");
+      setIsFixed(true);
+      alert("Schedule update successfully!");
+    } catch (error) {
+      console.error("Failed to update schedule:", error);
+      alert("Failed to update schedule.");
+    }
   };
 
   const handleCreateSchedule = async () => {
@@ -191,9 +244,7 @@ const SchedulePage = () => {
                 <div className="flex justify-center mt-4 space-x-4">
                   <button
                     className="px-4 py-2 font-bold text-white rounded bg-gradient-purple"
-                    onClick={() =>
-                      alert("Edit functionality not implemented yet")
-                    }
+                    onClick={handleEditSchedule}
                   >
                     Edit
                   </button>
@@ -247,12 +298,21 @@ const SchedulePage = () => {
                     </Label>
                   ))}
                 </div>
-                <button
-                  className="px-4 py-2 font-bold text-white rounded bg-gradient-pink"
-                  onClick={() => handleCreateSchedule()}
-                >
-                  Add Schedule
-                </button>
+                {isUpdateMode ? (
+                  <button
+                    className="px-4 py-2 font-bold text-white rounded bg-gradient-pink"
+                    onClick={() => handleUpdateSchedule()}
+                  >
+                    Update Schedule
+                  </button>
+                ) : (
+                  <button
+                    className="px-4 py-2 font-bold text-white rounded bg-gradient-pink"
+                    onClick={() => handleCreateSchedule()}
+                  >
+                    Add Schedule
+                  </button>
+                )}
               </>
             )}
           </div>
-- 
GitLab


From 0dae8af52cb815dc7b9dc0f3279a1a9beaebd119 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=84=9D=EC=B0=AC=20=EC=9C=A4?= <ysc0731@ajou.ac.kr>
Date: Fri, 6 Dec 2024 01:33:24 +0900
Subject: [PATCH 08/11] =?UTF-8?q?feat:=20=EC=8A=A4=EC=BC=80=EC=A5=B4=20upd?=
 =?UTF-8?q?ate=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80=20(#8)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/pages/SchedulePage.jsx | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/src/pages/SchedulePage.jsx b/src/pages/SchedulePage.jsx
index b796046..a68d221 100644
--- a/src/pages/SchedulePage.jsx
+++ b/src/pages/SchedulePage.jsx
@@ -116,6 +116,7 @@ const SchedulePage = () => {
       };
       // API 호출 부분 (주석 처리)
       // const newSchedule = await updateSchedule(scheduleData);
+
       // 임시로 더미 데이터에 추가
       const newSchedule = {
         ...scheduleData,
@@ -133,6 +134,8 @@ const SchedulePage = () => {
     } catch (error) {
       console.error("Failed to update schedule:", error);
       alert("Failed to update schedule.");
+    } finally {
+      setIsUpdateMode(false);
     }
   };
 
@@ -217,7 +220,7 @@ const SchedulePage = () => {
 
       {/* Sticky Container in Edit Mode */}
       {isEditMode && (
-        <div className="fixed bottom-0 right-0 flex items-center justify-center w-screen">
+        <div className="fixed bottom-0 right-0 flex items-center justify-center w-full ">
           <div
             className={`transform transition-transform w-full max-w-[768px] tablet:rounded-2xl bg-primary-100 p-6 text-center shadow-lg`}
           >
@@ -258,9 +261,15 @@ const SchedulePage = () => {
               </>
             ) : (
               <>
-                <h3 className="mb-4 heading-2 text-primary-500">
-                  Create New Schedule
-                </h3>
+                {isUpdateMode ? (
+                  <h3 className="mb-4 heading-2 text-primary-500">
+                    Update Schedule
+                  </h3>
+                ) : (
+                  <h3 className="mb-4 heading-2 text-primary-500">
+                    Create New Schedule
+                  </h3>
+                )}
                 <input
                   type="text"
                   value={newTitle}
-- 
GitLab


From b1d88b24fd4a9e99e3cbc17cc52be7e34f62fd4c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=84=9D=EC=B0=AC=20=EC=9C=A4?= <ysc0731@ajou.ac.kr>
Date: Fri, 6 Dec 2024 01:52:01 +0900
Subject: [PATCH 09/11] =?UTF-8?q?design:=20=EC=8A=A4=EC=BC=80=EC=A5=B4=20?=
 =?UTF-8?q?=EC=A0=9C=EB=AA=A9=20=EB=B0=8F=20=EC=88=98=EC=A0=95=EB=AA=A8?=
 =?UTF-8?q?=EB=93=9C=20=ED=86=A0=EA=B8=80=20=EC=83=89=EC=83=81=20=EB=B3=80?=
 =?UTF-8?q?=EA=B2=BD=20(#8)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/pages/SchedulePage.jsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/pages/SchedulePage.jsx b/src/pages/SchedulePage.jsx
index a68d221..3fd46fe 100644
--- a/src/pages/SchedulePage.jsx
+++ b/src/pages/SchedulePage.jsx
@@ -196,9 +196,9 @@ const SchedulePage = () => {
     <div className="min-h-screen bg-grayscale-50">
       {/* Toggle View/Edit Mode */}
       <div className="flex items-center justify-between p-4 bg-white shadow">
-        <h1 className="heading-1 text-primary-500">Schedule</h1>
+        <h1 className="heading-1">Schedule</h1>
         <label className="flex items-center space-x-3 cursor-pointer">
-          <span className="title-1 text-secondary-500">Edit Mode</span>
+          <span className="title-1 text-primary-500">Edit Mode</span>
           <div
             className={`relative w-12 h-6 rounded-full transition-colors ${
               isEditMode ? "bg-primary-500" : "bg-grayscale-300"
-- 
GitLab


From 6349e1e51bb0b984fc9140c8eb7bc7a948fe56f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=84=9D=EC=B0=AC=20=EC=9C=A4?= <ysc0731@ajou.ac.kr>
Date: Fri, 6 Dec 2024 02:15:29 +0900
Subject: [PATCH 10/11] =?UTF-8?q?feat:=20=EC=84=A0=ED=83=9D=EC=B7=A8?=
 =?UTF-8?q?=EC=86=8C=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EB=B0=9C=20=EB=B0=8F?=
 =?UTF-8?q?=20=EC=95=88=EB=82=B4=20=EB=A9=94=EC=84=B8=EC=A7=80=20=EC=88=98?=
 =?UTF-8?q?=EC=A0=95(#8)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/pages/SchedulePage.jsx | 121 +++++++++++++++++++++----------------
 1 file changed, 69 insertions(+), 52 deletions(-)

diff --git a/src/pages/SchedulePage.jsx b/src/pages/SchedulePage.jsx
index 3fd46fe..a39e13a 100644
--- a/src/pages/SchedulePage.jsx
+++ b/src/pages/SchedulePage.jsx
@@ -66,6 +66,19 @@ const SchedulePage = () => {
   const handleSlotClick = async (timeIdx) => {
     if (!isEditMode) return;
 
+    // API 호출 준비가 되었을 때 사용:
+    // try {
+    //   const response = await fetchScheduleByTimeIndex(timeIdx);
+    //   if (response && response.data && response.data.schedule) {
+    //     setSelectedSchedule(response.data.schedule); // API로 가져온 스케줄 설정
+    //   } else {
+    //     console.error("No schedule found for time index:", timeIdx);
+    //   }
+    // } catch (error) {
+    //   console.error("Failed to fetch schedule for time index:", timeIdx, error);
+    // }
+
+    //임시 코드
     const slotInSchedule = schedules.find((s) =>
       s.time_indices.includes(timeIdx)
     );
@@ -82,18 +95,13 @@ const SchedulePage = () => {
     } else {
       setSelectedSlots((prev) => [...prev, timeIdx]);
     }
+  };
 
-    // API 호출 준비가 되었을 때 사용:
-    // try {
-    //   const response = await fetchScheduleByTimeIndex(timeIdx);
-    //   if (response && response.data && response.data.schedule) {
-    //     setSelectedSchedule(response.data.schedule); // API로 가져온 스케줄 설정
-    //   } else {
-    //     console.error("No schedule found for time index:", timeIdx);
-    //   }
-    // } catch (error) {
-    //   console.error("Failed to fetch schedule for time index:", timeIdx, error);
-    // }
+  const handleCancelSchedule = () => {
+    setSelectedSlots([]);
+    setNewTitle("");
+    setIsFixed(true);
+    setSelectedSchedule(null);
   };
 
   const handleEditSchedule = () => {
@@ -130,10 +138,10 @@ const SchedulePage = () => {
       setSelectedSlots([]);
       setNewTitle("");
       setIsFixed(true);
-      alert("Schedule update successfully!");
+      alert("스케줄을 수정했습니다.!");
     } catch (error) {
-      console.error("Failed to update schedule:", error);
-      alert("Failed to update schedule.");
+      console.error("스케줄 수정에 실패했습니다.:", error);
+      alert("스케줄 수정에 실패했습니다.");
     } finally {
       setIsUpdateMode(false);
     }
@@ -162,10 +170,10 @@ const SchedulePage = () => {
       setSelectedSlots([]);
       setNewTitle("");
       setIsFixed(true);
-      alert("Schedule created successfully!");
+      alert("스케줄이 추가되었습니다!");
     } catch (error) {
-      console.error("Failed to create schedule:", error);
-      alert("Failed to create schedule.");
+      console.error("스케줄 삭제에 실패했습니다:", error);
+      alert("스케줄 추가에 실패했습니다.");
     }
   };
 
@@ -185,10 +193,11 @@ const SchedulePage = () => {
       setSchedules((prev) =>
         prev.filter((s) => s.title !== selectedSchedule.title)
       );
+
       setSelectedSchedule(null);
-      alert("Schedule deleted successfully!");
+      alert("스케줄이 삭제되었습니다.");
     } catch (error) {
-      console.error("Failed to delete schedule:", error);
+      console.error("스케줄 삭제에 실패했습니다:", error);
     }
   };
 
@@ -225,49 +234,49 @@ const SchedulePage = () => {
             className={`transform transition-transform w-full max-w-[768px] tablet:rounded-2xl bg-primary-100 p-6 text-center shadow-lg`}
           >
             {selectedSlots.length === 0 && selectedSchedule ? (
-              <>
-                <h3 className="mb-2 heading-2 text-primary-500">
-                  Schedule Details
-                </h3>
-                <p className="mb-1 body-1">
-                  <strong>Title:</strong> {selectedSchedule.title}
-                </p>
-                <p className="mb-1 body-1">
-                  <strong>Fixed:</strong>{" "}
-                  {selectedSchedule.is_fixed ? "고정" : "유동"}
-                </p>
-                <div className="mb-4 body-1">
-                  <span>Time Indices:</span>
-                  {selectedSchedule.time_indices.map((time_idx) => (
-                    <Label key={time_idx} theme="indigo" size="sm">
-                      {time_idx}
-                    </Label>
-                  ))}
+              <div className="flex flex-col items-center justify-center w-full">
+                <h3 className="mb-2 heading-2 text-primary-500">스케줄 정보</h3>
+                <div className="flex flex-col items-start w-1/2">
+                  <p className="mb-1 body-1">
+                    <strong>제목:</strong> {selectedSchedule.title}
+                  </p>
+                  <p className="mb-1 body-1">
+                    <strong>스케줄 타입:</strong>{" "}
+                    {selectedSchedule.is_fixed ? "고정" : "유동"}
+                  </p>
+                  <div className="mb-4 body-1">
+                    <strong>선택된 시간:</strong>{" "}
+                    {selectedSchedule.time_indices.map((time_idx) => (
+                      <Label key={time_idx} theme="indigo" size="sm">
+                        {time_idx}
+                      </Label>
+                    ))}
+                  </div>
                 </div>
                 <div className="flex justify-center mt-4 space-x-4">
                   <button
                     className="px-4 py-2 font-bold text-white rounded bg-gradient-purple"
                     onClick={handleEditSchedule}
                   >
-                    Edit
+                    수정하기
                   </button>
                   <button
                     className="px-4 py-2 font-bold text-white rounded bg-gradient-pink"
                     onClick={handleDeleteSchedule}
                   >
-                    Delete
+                    삭제하기
                   </button>
                 </div>
-              </>
+              </div>
             ) : (
               <>
                 {isUpdateMode ? (
                   <h3 className="mb-4 heading-2 text-primary-500">
-                    Update Schedule
+                    스케줄 수정하기
                   </h3>
                 ) : (
                   <h3 className="mb-4 heading-2 text-primary-500">
-                    Create New Schedule
+                    새 스케줄 만들기
                   </h3>
                 )}
                 <input
@@ -286,7 +295,7 @@ const SchedulePage = () => {
                       checked={isFixed === true}
                       onChange={() => setIsFixed(true)}
                     />
-                    <span className="body-1">고정</span>
+                    <span className="body-1">고정 스케줄</span>
                   </label>
                   <label className="flex items-center space-x-2">
                     <input
@@ -296,11 +305,11 @@ const SchedulePage = () => {
                       checked={isFixed === false}
                       onChange={() => setIsFixed(false)}
                     />
-                    <span className="body-1">유동</span>
+                    <span className="body-1">유동 스케줄</span>
                   </label>
                 </div>
                 <div className="mb-4 body-1">
-                  <span>Selected Slots:</span>
+                  <span>선택된 시간:</span>
                   {selectedSlots.map((time_idx) => (
                     <Label key={time_idx} theme="indigo" size="sm">
                       {time_idx}
@@ -312,15 +321,23 @@ const SchedulePage = () => {
                     className="px-4 py-2 font-bold text-white rounded bg-gradient-pink"
                     onClick={() => handleUpdateSchedule()}
                   >
-                    Update Schedule
+                    수정 완료
                   </button>
                 ) : (
-                  <button
-                    className="px-4 py-2 font-bold text-white rounded bg-gradient-pink"
-                    onClick={() => handleCreateSchedule()}
-                  >
-                    Add Schedule
-                  </button>
+                  <div className="flex justify-center mt-4 space-x-4">
+                    <button
+                      className="px-4 py-2 font-bold text-white rounded bg-tertiary-900"
+                      onClick={() => handleCancelSchedule()}
+                    >
+                      취소
+                    </button>
+                    <button
+                      className="px-4 py-2 font-bold text-white rounded bg-gradient-pink"
+                      onClick={() => handleCreateSchedule()}
+                    >
+                      추가
+                    </button>
+                  </div>
                 )}
               </>
             )}
-- 
GitLab


From eab6aed7fb2edef435716ccec3eaca105dbdbadd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=84=9D=EC=B0=AC=20=EC=9C=A4?= <ysc0731@ajou.ac.kr>
Date: Fri, 6 Dec 2024 02:26:30 +0900
Subject: [PATCH 11/11] =?UTF-8?q?feat:=20=EC=8A=A4=EC=BC=80=EC=A4=84=20?=
 =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20api=20=EC=A0=81=EC=9A=A9=20(#8)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/pages/SchedulePage.jsx | 175 +++++++++++++++++++------------------
 1 file changed, 91 insertions(+), 84 deletions(-)

diff --git a/src/pages/SchedulePage.jsx b/src/pages/SchedulePage.jsx
index a39e13a..5fa5f28 100644
--- a/src/pages/SchedulePage.jsx
+++ b/src/pages/SchedulePage.jsx
@@ -1,6 +1,12 @@
 import React, { useEffect, useState } from "react";
 import Label from "../components/Label";
-// import { createSchedule, deleteSchedule, fetchAllSchedules } from "./api"; // API 호출 주석 유지
+import {
+  createSchedule,
+  deleteSchedule,
+  fetchScheduleByTimeIndex,
+  fetchAllSchedules,
+  updateSchedule,
+} from "../api/schedule";
 
 const generateTimeSlots = () => {
   const timeSlots = [];
@@ -16,26 +22,26 @@ const generateTimeSlots = () => {
 
 const days = ["월", "화", "수", "목", "금", "토", "일"];
 
-const dummySchedules = [
-  {
-    id: 1,
-    user_id: 1,
-    title: "알고리즘 스터디",
-    is_fixed: true,
-    time_indices: [36, 37, 38, 39],
-    createdAt: "2024-12-02T09:52:00.000Z",
-    updatedAt: "2024-12-02T09:52:00.000Z",
-  },
-  {
-    id: 5,
-    user_id: 1,
-    title: "웹시설 팀플",
-    is_fixed: true,
-    time_indices: [165, 166, 167, 255, 256, 257],
-    createdAt: "2024-12-02T09:54:53.000Z",
-    updatedAt: "2024-12-02T09:54:53.000Z",
-  },
-];
+// const dummySchedules = [
+//   {
+//     id: 1,
+//     user_id: 1,
+//     title: "알고리즘 스터디",
+//     is_fixed: true,
+//     time_indices: [36, 37, 38, 39],
+//     createdAt: "2024-12-02T09:52:00.000Z",
+//     updatedAt: "2024-12-02T09:52:00.000Z",
+//   },
+//   {
+//     id: 5,
+//     user_id: 1,
+//     title: "웹시설 팀플",
+//     is_fixed: true,
+//     time_indices: [165, 166, 167, 255, 256, 257],
+//     createdAt: "2024-12-02T09:54:53.000Z",
+//     updatedAt: "2024-12-02T09:54:53.000Z",
+//   },
+// ];
 
 const SchedulePage = () => {
   const timeSlots = generateTimeSlots();
@@ -48,53 +54,54 @@ const SchedulePage = () => {
   const [isFixed, setIsFixed] = useState(true);
 
   useEffect(() => {
-    // const initializeSchedules = async () => {
-    //   try {
-    //     const data = await fetchAllSchedules();
-    //     setSchedules(data);
-    //   } catch (error) {
-    //     console.error("Failed to load schedules", error);
-    //   }
-    // };
+    // API
+    const initializeSchedules = async () => {
+      try {
+        const data = await fetchAllSchedules();
+        setSchedules(data);
+      } catch (error) {
+        console.error("Failed to load schedules", error);
+      }
+    };
 
-    // initializeSchedules();
+    initializeSchedules();
 
-    // 현재는 더미 데이터로 초기화
-    setSchedules(dummySchedules);
+    // 임시 코드
+    // setSchedules(dummySchedules);
   }, []);
 
   const handleSlotClick = async (timeIdx) => {
     if (!isEditMode) return;
 
-    // API 호출 준비가 되었을 때 사용:
-    // try {
-    //   const response = await fetchScheduleByTimeIndex(timeIdx);
-    //   if (response && response.data && response.data.schedule) {
-    //     setSelectedSchedule(response.data.schedule); // API로 가져온 스케줄 설정
-    //   } else {
-    //     console.error("No schedule found for time index:", timeIdx);
-    //   }
-    // } catch (error) {
-    //   console.error("Failed to fetch schedule for time index:", timeIdx, error);
-    // }
-
-    //임시 코드
-    const slotInSchedule = schedules.find((s) =>
-      s.time_indices.includes(timeIdx)
-    );
-
-    if (slotInSchedule) {
-      if (selectedSlots.length === 0) {
-        setSelectedSchedule(slotInSchedule);
+    // API
+    try {
+      const response = await fetchScheduleByTimeIndex(timeIdx);
+      if (response && response.data && response.data.schedule) {
+        setSelectedSchedule(response.data.schedule); // API로 가져온 스케줄 설정
+      } else {
+        console.error("No schedule found for time index:", timeIdx);
       }
-      return;
+    } catch (error) {
+      console.error("Failed to fetch schedule for time index:", timeIdx, error);
     }
 
-    if (selectedSlots.includes(timeIdx)) {
-      setSelectedSlots((prev) => prev.filter((idx) => idx !== timeIdx));
-    } else {
-      setSelectedSlots((prev) => [...prev, timeIdx]);
-    }
+    // 임시 코드
+    // const slotInSchedule = schedules.find((s) =>
+    //   s.time_indices.includes(timeIdx)
+    // );
+
+    // if (slotInSchedule) {
+    //   if (selectedSlots.length === 0) {
+    //     setSelectedSchedule(slotInSchedule);
+    //   }
+    //   return;
+    // }
+
+    // if (selectedSlots.includes(timeIdx)) {
+    //   setSelectedSlots((prev) => prev.filter((idx) => idx !== timeIdx));
+    // } else {
+    //   setSelectedSlots((prev) => [...prev, timeIdx]);
+    // }
   };
 
   const handleCancelSchedule = () => {
@@ -122,16 +129,16 @@ const SchedulePage = () => {
         is_fixed: isFixed,
         time_indices: selectedSlots,
       };
-      // API 호출 부분 (주석 처리)
-      // const newSchedule = await updateSchedule(scheduleData);
-
-      // 임시로 더미 데이터에 추가
-      const newSchedule = {
-        ...scheduleData,
-        id: Date.now(),
-        createdAt: new Date().toISOString(),
-        updatedAt: new Date().toISOString(),
-      };
+      // API
+      const newSchedule = await updateSchedule(scheduleData);
+
+      // 임시 코드
+      // const newSchedule = {
+      //   ...scheduleData,
+      //   id: Date.now(),
+      //   createdAt: new Date().toISOString(),
+      //   updatedAt: new Date().toISOString(),
+      // };
 
       setSchedules((prev) => [...prev, newSchedule]);
       setSelectedSchedule(newSchedule);
@@ -155,16 +162,16 @@ const SchedulePage = () => {
         time_indices: selectedSlots,
       };
 
-      // API 호출 부분 (주석 처리)
-      // const newSchedule = await createSchedule(scheduleData);
+      // API
+      const newSchedule = await createSchedule(scheduleData);
 
-      // 임시로 더미 데이터에 추가
-      const newSchedule = {
-        ...scheduleData,
-        id: Date.now(),
-        createdAt: new Date().toISOString(),
-        updatedAt: new Date().toISOString(),
-      };
+      // 임시코드
+      // const newSchedule = {
+      //   ...scheduleData,
+      //   id: Date.now(),
+      //   createdAt: new Date().toISOString(),
+      //   updatedAt: new Date().toISOString(),
+      // };
 
       setSchedules((prev) => [...prev, newSchedule]);
       setSelectedSlots([]);
@@ -184,15 +191,15 @@ const SchedulePage = () => {
       const body = { title: selectedSchedule.title };
 
       // API 호출 준비가 되었을 때 사용:
-      // await deleteSchedule(body);
+      await deleteSchedule(body);
 
-      // const updatedSchedules = await fetchAllSchedules();
-      // setSchedules(updatedSchedules);
+      const updatedSchedules = await fetchAllSchedules();
+      setSchedules(updatedSchedules);
 
-      // 임시로 삭제 처리
-      setSchedules((prev) =>
-        prev.filter((s) => s.title !== selectedSchedule.title)
-      );
+      // 임시코드
+      // setSchedules((prev) =>
+      //   prev.filter((s) => s.title !== selectedSchedule.title)
+      // );
 
       setSelectedSchedule(null);
       alert("스케줄이 삭제되었습니다.");
-- 
GitLab