diff --git a/FE/error/public/Profile.png b/FE/error/public/Profile.png new file mode 100644 index 00000000..ab8a9297 Binary files /dev/null and b/FE/error/public/Profile.png differ diff --git a/FE/error/public/seed0838.png b/FE/error/public/seed0838.png new file mode 100644 index 00000000..a3194054 Binary files /dev/null and b/FE/error/public/seed0838.png differ diff --git a/FE/error/src/axiosConfig.js b/FE/error/src/axiosConfig.js index f70e5442..907b9aef 100644 --- a/FE/error/src/axiosConfig.js +++ b/FE/error/src/axiosConfig.js @@ -1,80 +1,6 @@ import axios from "axios"; -import { useNavigate } from "react-router-dom"; // Axios 기본 설정 axios.defaults.baseURL = import.meta.env.VITE_ERROR_API; axios.defaults.headers.common["Content-Type"] = "application/json"; axios.defaults.withCredentials = true; - -let isRefreshing = false; -let refreshSubscribers = []; - -const onRefreshed = (token) => { - refreshSubscribers.map((cb) => cb(token)); -}; - -const addRefreshSubscriber = (cb) => { - refreshSubscribers.push(cb); -}; - -axios.interceptors.request.use( - (config) => { - const token = localStorage.getItem("slackToken"); - if (token) { - config.headers["Authorization"] = `Bearer ${token}`; - } - return config; - }, - (error) => { - return Promise.reject(error); - } -); - -axios.interceptors.response.use( - (response) => { - return response; - }, - async (error) => { - const originalRequest = error.config; - if (error.response.status === 401 && !originalRequest._retry) { - if (isRefreshing) { - return new Promise((resolve) => { - addRefreshSubscriber((token) => { - originalRequest.headers["Authorization"] = "Bearer " + token; - resolve(axios(originalRequest)); - }); - }); - } - - originalRequest._retry = true; - isRefreshing = true; - - const refreshToken = localStorage.getItem("refreshToken"); - - return new Promise((resolve, reject) => { - axios - .post("/auth/reissue", { refreshToken: refreshToken }) - .then(({ data }) => { - const newToken = data.data.accessToken; - localStorage.setItem("slackToken", newToken); - axios.defaults.headers.common["Authorization"] = - "Bearer " + newToken; - originalRequest.headers["Authorization"] = "Bearer " + newToken; - onRefreshed(newToken); - resolve(axios(originalRequest)); - }) - .catch((err) => { - reject(err); - useNavigate().push("/login"); - }) - .finally(() => { - isRefreshing = false; - refreshSubscribers = []; - }); - }); - } - return Promise.reject(error); - } -); - -export default axios; diff --git a/FE/error/src/components/DeleteEvent.jsx b/FE/error/src/components/DeleteEvent.jsx index b69a7826..3a6e16c4 100644 --- a/FE/error/src/components/DeleteEvent.jsx +++ b/FE/error/src/components/DeleteEvent.jsx @@ -7,9 +7,15 @@ const DeleteEvent = ({ onRequestClose, handleUpdateDeleteData, }) => { + const storedToken = localStorage.getItem("slackToken"); + const calendarDelete = () => { axios - .delete("/api/calendar/" + selectID) + .delete(`/api/calendar/${selectID}`, { + headers: { + Authorization: `Bearer ${storedToken}`, + }, + }) .then(() => { handleUpdateDeleteData(selectID); handleDelete(); diff --git a/FE/error/src/components/EconoCalendar.jsx b/FE/error/src/components/EconoCalendar.jsx index 814eae47..8e52858e 100644 --- a/FE/error/src/components/EconoCalendar.jsx +++ b/FE/error/src/components/EconoCalendar.jsx @@ -25,13 +25,10 @@ const EconoCalendar = ({ isLoggedIn, setIsLoggedIn }) => { const uri = isUserLoggedIn ? "/api/calendar/all" - : "/api/calendar/public/all"; - const config = isUserLoggedIn - ? { headers: { Authorization: `Bearer ${storedToken}` } } - : {}; + : "/api/calendar/all/public"; axios - .get(uri, config) + .get(uri, { headers: { Authorization: `Bearer ${storedToken}` } }) .then((res) => { const fetchedEvents = res.data.data.map((event) => ({ title: event.eventName, @@ -292,7 +289,7 @@ const CalendarContainer = styled.div` background-color: #fff; border-color: #cbcbcb; color: #595959; - margin-right: 0.7rem; + margin-right: 1rem; } .fc-event-title-container { height: 1.3rem; @@ -301,4 +298,7 @@ const CalendarContainer = styled.div` font-size: 0.95rem; margin-left: 0.3rem; } + .fc-direction-ltr .fc-toolbar > * > :not(:first-child) { + margin-left: 0.5rem; + } `; diff --git a/FE/error/src/components/SideBar/ProfileBar.jsx b/FE/error/src/components/SideBar/ProfileBar.jsx index 2f72a1aa..c6d11be2 100644 --- a/FE/error/src/components/SideBar/ProfileBar.jsx +++ b/FE/error/src/components/SideBar/ProfileBar.jsx @@ -1,12 +1,66 @@ import styled from "styled-components"; +import { useState } from "react"; +import { HiPencil } from "react-icons/hi2"; +import { useNavigate } from "react-router-dom"; const ProfileBar = () => { - return ; + const [isHovered, setIsHovered] = useState(false); + const navigate = useNavigate(); + + const handleProfileClick = () => { + navigate("/profile"); + }; + + return ( + + setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + onClick={handleProfileClick} + > + + {isHovered && ( + + + + )} + + + ); }; export default ProfileBar; const StyledProfileFrame = styled.div` - width: 20rem; - height: 18.4375rem; + width: 15.625rem; + height: 15rem; + align-items: center; + display: flex; + flex-direction: column; + margin-bottom: 0.6rem; +`; + +const ProfileImageContainer = styled.div` + position: relative; + cursor: pointer; +`; + +const ProfileImage = styled.img` + margin-top: 1.25rem; + width: 13rem; +`; + +const EditIconOverlay = styled.div` + position: absolute; + top: 1rem; + left: 0; + right: 0; + bottom: 0; + border-radius: 50%; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + color: white; + font-size: 2rem; `; diff --git a/FE/error/src/components/SideBar/individualFilter/IndividualFilter.jsx b/FE/error/src/components/SideBar/individualFilter/IndividualFilter.jsx index eda403f9..c31c60b8 100644 --- a/FE/error/src/components/SideBar/individualFilter/IndividualFilter.jsx +++ b/FE/error/src/components/SideBar/individualFilter/IndividualFilter.jsx @@ -6,7 +6,11 @@ import styled from "styled-components"; import FilterCreateModal from "../../../utils/filterUtils/FilterCreateModal"; import FilterList from "../../../utils/filterUtils/FilterList"; -const IndividualFilter = ({ filterLists, addNewFilter }) => { +const IndividualFilter = ({ + filterLists, + addNewFilter, + updateDeleteFilter, +}) => { const [individualFilterIsOpen, setindividualFilterIsOpen] = useState(false); const [filterListsIsOpen, setFilterListsIsOpen] = useState(true); const createIndividualFilter = () => { @@ -16,6 +20,7 @@ const IndividualFilter = ({ filterLists, addNewFilter }) => { const handleArrowDown = () => { setFilterListsIsOpen(!filterListsIsOpen); }; + return ( <> @@ -60,7 +65,12 @@ const IndividualFilter = ({ filterLists, addNewFilter }) => { /> - {filterListsIsOpen && } + {filterListsIsOpen && ( + + )} ); }; diff --git a/FE/error/src/components/scheduleCheck/CheckCalendar.jsx b/FE/error/src/components/scheduleCheck/CheckCalendar.jsx index 8fe3df22..2424f0b8 100644 --- a/FE/error/src/components/scheduleCheck/CheckCalendar.jsx +++ b/FE/error/src/components/scheduleCheck/CheckCalendar.jsx @@ -21,6 +21,7 @@ const CheckCalendar = ({ handleUpdateDeleteData, }) => { const [event, setEvent] = useState({}); + const storedToken = localStorage.getItem("slackToken"); function createDate(title, startDate, endDate, place, info, type, color) { const specificEvent = { @@ -42,17 +43,21 @@ const CheckCalendar = ({ return; } - axios.get("/api/calendar/" + selectID).then((res) => { - createDate( - res.data.data.eventName, - res.data.data.eventStartDate, - res.data.data.eventEndDate, - res.data.data.eventPlace, - res.data.data.eventInfo, - res.data.data.eventType, - res.data.data.filterColor - ); - }); + axios + .get("/api/calendar/" + selectID, { + headers: { Authorization: `Bearer ${storedToken}` }, + }) + .then((res) => { + createDate( + res.data.data.eventName, + res.data.data.eventStartDate, + res.data.data.eventEndDate, + res.data.data.eventPlace, + res.data.data.eventInfo, + res.data.data.eventType, + res.data.data.filterColor + ); + }); }, [selectID]); function date(startDate, endDate) { diff --git a/FE/error/src/components/scheduleCreate/CreateModal.jsx b/FE/error/src/components/scheduleCreate/CreateModal.jsx index ae74644c..cfa40859 100644 --- a/FE/error/src/components/scheduleCreate/CreateModal.jsx +++ b/FE/error/src/components/scheduleCreate/CreateModal.jsx @@ -29,6 +29,7 @@ const CreateModal = ({ const [eventEndTime, setEventEndTime] = useState("00:00"); const [selectedFilter, setSelectedFilter] = useState(null); const [activeDropdown, setActiveDropdown] = useState(null); + const [privateFilters, setPrivateFilters] = useState([]); useEffect(() => { if (isOpen && selectedDate) { @@ -38,16 +39,32 @@ const CreateModal = ({ setEventInfo(""); setEventPlace(""); setEventMemo(""); - setEventStartTime("00:00"); // 초기화 추가 - setEventEndTime("00:00"); // 초기화 추가 - setNewStartDate(selectedDate + "T00:00"); // 수정 - setNewEndDate(selectedDate + "T00:00"); // 수정 - + setEventStartTime("00:00"); + setEventEndTime("00:00"); + setNewStartDate(selectedDate + "T00:00"); + setNewEndDate(selectedDate + "T00:00"); setSelectedFilter(null); setActiveDropdown(null); + + fetchFilters(); } }, [isOpen, selectedDate]); + const storedToken = localStorage.getItem("slackToken"); + + const fetchFilters = async () => { + try { + const response = await axios.get("/api/filter", { + headers: { Authorization: `Bearer ${storedToken}` }, + }); + if (response.data && response.data.data) { + setPrivateFilters(response.data.data); + } + } catch (error) { + console.error("필터 정보를 가져오는 데 실패했습니다:", error); + } + }; + const isFilterSelected = () => { return selectedFilter && selectedFilter.category && selectedFilter.filter; }; @@ -82,7 +99,6 @@ const CreateModal = ({ setEventStartTime(time); setNewStartDate(`${StartDate}T${time}`); - // 시작 시간이 종료 시간보다 늦을 경우, 종료 시간을 시작 시간과 같게 설정 if (StartDate === EndDate && time > eventEndTime) { setEventEndTime(time); setNewEndDate(`${EndDate}T${time}`); @@ -91,7 +107,6 @@ const CreateModal = ({ const handleEndTimeSelect = (time) => { if (StartDate === EndDate && time < eventStartTime) { - // 종료 시간이 시작 시간보다 이를 경우, 시작 시간을 종료 시간과 같게 설정 setEventStartTime(time); setNewStartDate(`${StartDate}T${time}`); } @@ -122,11 +137,11 @@ const CreateModal = ({ return selectedFilter.filter; } switch (category) { - case "econo": + case "public": return "에코노"; case "group": return "그룹"; - case "personal": + case "private": return "개인"; default: return ""; @@ -146,7 +161,7 @@ const CreateModal = ({ const saveData = () => { if (!eventName || !isFilterSelected()) { - return; // 추가적인 안전장치 + return; } const data = { @@ -155,20 +170,27 @@ const CreateModal = ({ eventEndDate: eventEndDate, eventPlace: eventPlace, eventInfo: eventMemo, - eventCategory: { - [selectedFilter.category]: selectedFilter.filter, - }, + scheduleType: selectedFilter.category, + filterName: selectedFilter.filter, }; - axios.post("/api/calendar", data).then((res) => { - createDate( - eventName, - res.data.data.eventId, - eventStartDate, - eventEndDate - ); - onRequestClose(); - }); + axios + .post( + "/api/calendar", + { + headers: { Authorization: `Bearer ${storedToken}` }, + }, + data + ) + .then((res) => { + createDate( + eventName, + res.data.data.eventId, + eventStartDate, + eventEndDate + ); + onRequestClose(); + }); }; return ( @@ -191,7 +213,7 @@ const CreateModal = ({ - {["econo", "group", "personal"].map((category) => ( + {["public", "group", "private"].map((category) => (