diff --git a/app/screens/ScheduleAddModal.js b/app/screens/ScheduleAddModal.js index 90050a5..d7edae6 100644 --- a/app/screens/ScheduleAddModal.js +++ b/app/screens/ScheduleAddModal.js @@ -1,4 +1,4 @@ -import React, { useRef, useState, useMemo, useEffect } from "react"; +import React, { useRef, useState, useEffect, useMemo } from "react"; import { View, Text, @@ -17,7 +17,6 @@ import { pad } from "./ScheduleList"; const SCREEN_HEIGHT = Dimensions.get("window").height; const SCREEN_PAD = 32; -// 중요도 옵션 (API 값: value) const importanceOptions = [ { label: "매우 중요", value: "S", color: "#FFB7B7" }, { label: "보통", value: "I", color: "#FFCB82" }, @@ -29,34 +28,17 @@ export default function ScheduleAddModal({ onClose, selectedDate, onSave, - isEditing, + isEditing = false, + editData = null, saving, }) { const modalAddRef = useRef(null); - React.useEffect(() => { - if (visible) { - setHour(""); - setMinute(""); - setTempHour("00"); - setTempMinute("00"); - modalAddRef.current?.open(); - } else { - modalAddRef.current?.close(); - } - }, [visible]); - - React.useEffect(() => { - // 시간 또는 분이 변경되면 별도 처리 가능 (필요시) - console.log("시간 변경: ", hour, minute); - }, [hour, minute]); - const [title, setTitle] = useState(""); const [hour, setHour] = useState(""); const [minute, setMinute] = useState(""); const [tempHour, setTempHour] = useState("00"); const [tempMinute, setTempMinute] = useState("00"); - // 중요도 초기값 반드시 API value ("S"/"I"/"N") const [priority, setPriority] = useState(""); const [memo, setMemo] = useState(""); const [showTimePicker, setShowTimePicker] = useState(false); @@ -65,103 +47,134 @@ export default function ScheduleAddModal({ const [priorityRequired, setPriorityRequired] = useState(false); const [saveError, setSaveError] = useState(""); - const hourList = useMemo( - () => Array.from({ length: 24 }, (_, i) => pad(i)), - [] - ); - const minuteList = useMemo( - () => Array.from({ length: 60 }, (_, i) => pad(i)), - [] - ); + const hourList = useMemo(() => Array.from({ length: 24 }, (_, i) => pad(i)), []); + const minuteList = useMemo(() => Array.from({ length: 60 }, (_, i) => pad(i)), []); - const openPicker = () => { - setTempHour(hour || "00"); - setTempMinute(minute || "00"); - setShowTimePicker(true); + useEffect(() => { + if (visible) { + if (isEditing && editData) { + setTitle(editData.title || ""); + setHour(editData.hour || ""); + setMinute(editData.minute || ""); + if(editData.priority === "S" || editData.priority === "매우 중요") { + setPriority("S"); + } else if(editData.priority === "X" || editData.priority === "중요하지 않음") { + setPriority("N"); + } else if(editData.priority === "I" || editData.priority === "중요") { + setPriority("I"); + } else { + setPriority("I"); // 기본값 + } + setMemo(editData.memo || ""); + setTempHour(editData.hour || "00"); + setTempMinute(editData.minute || "00"); + } else { + setTitle(""); + setHour(""); + setMinute(""); + setPriority(""); + setMemo(""); + } + setSaveError(""); + modalAddRef.current?.open(); + } else { + modalAddRef.current?.close(); + } + }, [visible, isEditing, editData]); + + const handleModalClosed = () => { + setTempHour("00"); + setTempMinute("00"); + handleCancel(); }; - // API 요구 포맷으로 반환 (예: 2025-09-13 10:00:00) const getApiDateTime = () => { - // selectedDate가 JS Date 객체이어야 함! const dateObj = new Date(selectedDate); const yyyy = dateObj.getFullYear(); const mm = pad(dateObj.getMonth() + 1); const dd = pad(dateObj.getDate()); - const h = hour !== "" ? pad(hour) : "00"; - const m = minute !== "" ? pad(minute) : "00"; return `${yyyy}-${mm}-${dd} ${pad(hour)}:${pad(minute)}:00`; }; const handleSave = () => { - const isTitleValid = title.trim() !== ""; - if (!isTitleValid) { - setTitleRequired(true); - setPriorityRequired(false); - setTimeRequired(false); - return; - } else { - setTitleRequired(false); - } + if (title.trim() === "") { + setTitleRequired(true); + setPriorityRequired(false); + setTimeRequired(false); + return; + } else { + setTitleRequired(false); + } - const isTimeValid = hour !== "" && minute !== ""; - if (!isTimeValid) { - setTimeRequired(true); - return; - } else { - setTimeRequired(false); - } + if (hour === "" || minute === "") { + setTimeRequired(true); + return; + } else { + setTimeRequired(false); + } - const isPriorityValid = priority !== ""; - if (!isPriorityValid) { - setPriorityRequired(true); - setTimeRequired(false); - return; - } else { - setPriorityRequired(false); - } + if (priority === "") { + setPriorityRequired(true); + setTimeRequired(false); + return; + } else { + setPriorityRequired(false); + } - if (title.length > 7) { - return; - } + if (title.length > 7) { + return; + } AsyncStorage.getItem("userId") .then((userId) => { - return axios.get(`${process.env.EXPO_PUBLIC_API_URL}/calendar/add`, { - params: { - userId, - title, - time: getApiDateTime(), - importance: priority, // 반드시 "S" | "I" | "N" - memo, - }, - withCredentials: true - }); + if (!userId) { + throw new Error("사용자 정보가 없습니다."); + } + + const params = { + userId, + title, + time: getApiDateTime(), + importance: priority, + memo, + }; + + if (isEditing && editData?.id) { + return axios.get(`${process.env.EXPO_PUBLIC_API_URL}/calendar/update`, { + params: { ...params, calendar_id: editData.id }, + withCredentials: true, + }); + } else { + return axios.get(`${process.env.EXPO_PUBLIC_API_URL}/calendar/add`, { + params, + withCredentials: true, + }); + } }) .then((res) => { - const calendarId = res.data.calendarId || res.data.id; - if (calendarId) { - AsyncStorage.setItem("calendarId", calendarId.toString()); - } - console.log("[schedule add] Response:", res.data); + const calendarId = isEditing ? editData.id : res.data.calendarId || res.data.id; onSave && onSave({ + id: calendarId, title, hour, minute, priority, memo, - calendarId }); handleCancel(); }) .catch((err) => { - setSaveError( - "일정 저장 실패: " + (err?.response?.data?.message || err.message) - ); - console.error("[schedule add] Error:", err?.response?.data || err); + setSaveError("일정 저장 실패: " + (err?.response?.data?.message || err.message)); }); }; + const openPicker = () => { + setTempHour(hour || "00"); + setTempMinute(minute || "00"); + setShowTimePicker(true); + }; + const handleCancel = () => { setTitle(""); setHour(""); @@ -175,19 +188,15 @@ export default function ScheduleAddModal({ onClose && onClose(); }; - // 한글 라벨 반환 (API 값 → label) - const getPriorityLabel = (val) => - importanceOptions.find((opt) => opt.value === val)?.label ?? ""; - return ( 면접시간 - - setShowTimePicker(true)}> - - {hour || minute ? `${hour || "00"}:${minute || "00"}` : "시간을 선택하세요."} - - {timeRequired && 시간을 선택해 주세요.} - + + + + {hour || minute ? `${hour || "00"}:${minute || "00"}` : "시간을 선택하세요."} + + + {timeRequired && ( + 시간을 선택해 주세요. + )} + 중요도 - - - {importanceOptions.map((opt) => { - const selected = priority === opt.value; - return ( - { - setPriority(opt.value); - setPriorityRequired(false); - }} - > - - {opt.label} - - - ); - })} - - {priorityRequired && ( - 중요도를 선택해 주세요 - )} + + + {importanceOptions.map((opt) => { + const selected = priority === opt.value; + return ( + { + setPriority(opt.value); + setPriorityRequired(false); + }} + > + + {opt.label} + + + ); + })} + + {priorityRequired && ( + 중요도를 선택해 주세요 + )} @@ -287,7 +302,7 @@ export default function ScheduleAddModal({ multiline value={memo} onChangeText={(text) => { - if (text.length <= 49) { // 50자 미만(49자 이하) 제한 + if (text.length <= 49) { setMemo(text); } }} @@ -311,24 +326,27 @@ export default function ScheduleAddModal({ {showTimePicker && ( - + }} + > - { - setShowTimePicker(false); - // wheel picker의 임시값 초기화 - setTempHour("00"); - setTempMinute("00"); - }}> + { + setShowTimePicker(false); + }} + > 취소 - { - setShowTimePicker(false); - setHour(tempHour); - setMinute(tempMinute); - }}> + { + setShowTimePicker(false); + setHour(tempHour); + setMinute(tempMinute); + }} + > 확인 @@ -371,11 +389,16 @@ const styles = StyleSheet.create({ }, inputRow: { flexDirection: "row", - alignItems: "stretch", + alignItems: "center", marginBottom: 10, minHeight: 50, }, - label: { fontWeight: "bold", width: 80, fontSize: 15, marginTop: 4 }, + label: { + fontWeight: "bold", + width: 80, + fontSize: 15, + marginTop: 4 + }, input: { flex: 1, borderWidth: 1, @@ -395,6 +418,7 @@ const styles = StyleSheet.create({ textAlignVertical: "top", }, footerButtons: { + flex:1, flexDirection: "row", justifyContent: "space-between", paddingVertical: 10, @@ -413,7 +437,9 @@ const styles = StyleSheet.create({ borderRadius: 10, }, required: { color: "red", marginLeft: 6, fontSize: 16 }, - priorityBox: { flexDirection: "row", gap: 8 }, + priorityBox: { + flexDirection: "row", + gap: 7 }, priorityBtn: { width: 84, alignItems: "center", @@ -440,7 +466,7 @@ const styles = StyleSheet.create({ backgroundColor: "#fff", paddingBottom: 20, justifyContent: "center", - height: 270 + height: 270, }, errorMsg: { color: "#FF5A5A", diff --git a/app/screens/ScheduleList.js b/app/screens/ScheduleList.js index fc53ac4..6b5faaa 100644 --- a/app/screens/ScheduleList.js +++ b/app/screens/ScheduleList.js @@ -46,8 +46,6 @@ export default function ScheduleList({ modalRef, schedules, selectedDate, - onOpenEditModal, - onOpenDeleteModal, onModalOpen, onModalClose, showFAB, @@ -60,15 +58,31 @@ export default function ScheduleList({ const [addModalVisible, setAddModalVisible] = useState(false); const [hideFAB, setHideFAB] = useState(false); + + const [isEditing, setIsEditing] = useState(false); // 수정 모드 상태 + const [editData, setEditData] = useState(null); // 수정 대상 일정 + + const scheduleArr = schedules[selectedDate] || []; + + const onOpenEditModal = (item, idx) => { + setIsEditing(true); + setEditData(item); + setAddModalVisible(true); + setHideFAB(true); + }; + const handleOpenAddModal = () => { + setIsEditing(false); + setEditData(null); setAddModalVisible(true); setHideFAB(true); }; const handleCloseAddModal = () => { + setIsEditing(false); + setEditData(null); setAddModalVisible(false); setHideFAB(false); }; - const scheduleArr = schedules[selectedDate] || []; const handleConfirmDelete = () => { if (deleteIdx == null) return; @@ -130,8 +144,10 @@ export default function ScheduleList({ contentContainerStyle={{ paddingBottom: 24 }} showsVerticalScrollIndicator={false} > - {schedules[selectedDate]?.length ? ( - schedules[selectedDate] + + {scheduleArr.length ? ( + scheduleArr + .sort((a, b) => `${a.hour}${a.minute}`.localeCompare(`${b.hour}${b.minute}`) ) @@ -200,7 +216,12 @@ export default function ScheduleList({ visible={addModalVisible} onClose={handleCloseAddModal} selectedDate={selectedDate} - onSave={onSave} + onSave={() => { + onSave && onSave(); + handleCloseAddModal(); + }} + isEditing={isEditing} + editData={editData} /> {showFAB && !hideFAB && (