From f154ab192db3c29bab1e84deee89ba871c5ba456 Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Mon, 17 Nov 2025 23:50:46 +0900 Subject: [PATCH 01/29] =?UTF-8?q?chore:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20?= =?UTF-8?q?=EC=A7=84=EC=9E=85=20=EB=B2=84=ED=8A=BC=20svg=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commons/svgs/AdminButton.jsx | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/commons/svgs/AdminButton.jsx diff --git a/src/commons/svgs/AdminButton.jsx b/src/commons/svgs/AdminButton.jsx new file mode 100644 index 0000000..dcdfe6f --- /dev/null +++ b/src/commons/svgs/AdminButton.jsx @@ -0,0 +1,7 @@ +export const AdminButton = () => { + return ( + + + + ); +}; From 5e727f2ad340fec80f3a8af532597c417b076521 Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Mon, 17 Nov 2025 23:51:41 +0900 Subject: [PATCH 02/29] =?UTF-8?q?feat:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20?= =?UTF-8?q?=EC=A7=84=EC=9E=85=20=EB=B2=84=ED=8A=BC=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EB=B0=8F=20home=20=ED=99=94=EB=A9=B4=20=EB=B0=B0=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/home/EnterAdmin.jsx | 32 ++++++++++++++++++++++++++++++ src/components/home/Home.jsx | 2 ++ 2 files changed, 34 insertions(+) create mode 100644 src/components/home/EnterAdmin.jsx diff --git a/src/components/home/EnterAdmin.jsx b/src/components/home/EnterAdmin.jsx new file mode 100644 index 0000000..9c9296f --- /dev/null +++ b/src/components/home/EnterAdmin.jsx @@ -0,0 +1,32 @@ +import { AdminButton } from "commons/svgs/AdminButton"; +import React from "react"; +import { useNavigate } from "react-router-dom"; +import "styles/components/home/EnterAdmin.scss"; + +export default function EnterAdmin() { + const navigate = useNavigate(); + + const handleClick = () => { + navigate("/admin"); + }; + + const handleKeyDown = (e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + handleClick(); + } + }; + + return ( + + ); +} diff --git a/src/components/home/Home.jsx b/src/components/home/Home.jsx index ecf1a1e..8e3c63f 100644 --- a/src/components/home/Home.jsx +++ b/src/components/home/Home.jsx @@ -13,6 +13,7 @@ import "styles/components/home/Home.scss"; import { getAuthToken } from "utils/token"; import { getUserInfo } from "utils/user"; import { RankingPreview } from "./RankingPreview"; +import EnterAdmin from "./EnterAdmin"; const rankingData = [ { username: "Player1", score: 1000 }, { username: "Player2", score: 900 }, @@ -95,6 +96,7 @@ const Home = () => { + ); }; From 08cf0e42d0503484ff66359a0536b80b0fe65040 Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Mon, 17 Nov 2025 23:51:58 +0900 Subject: [PATCH 03/29] =?UTF-8?q?design:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=86=8D?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/components/home/EnterAdmin.scss | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/styles/components/home/EnterAdmin.scss diff --git a/src/styles/components/home/EnterAdmin.scss b/src/styles/components/home/EnterAdmin.scss new file mode 100644 index 0000000..522c802 --- /dev/null +++ b/src/styles/components/home/EnterAdmin.scss @@ -0,0 +1,24 @@ +.admin-button { + position: fixed; + right: 24px; + bottom: 24px; + z-index: 1000; + width: 56px; + height: 56px; + border-radius: 50%; + border: none; + background: #1976d2; + color: #fff; + box-shadow: 0 6px 18px rgba(0, 0, 0, 0.2); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + padding: 0; + + svg { + width: 24px; + height: 24px; + display: block; + } +} From f011184827b63857399ffbf56b0ea0c39dbd813f Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Tue, 18 Nov 2025 01:01:13 +0900 Subject: [PATCH 04/29] =?UTF-8?q?feat:=20admin=20=EB=9D=BC=EC=9A=B0?= =?UTF-8?q?=ED=8C=85=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/admin.js | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/routes/root.js | 3 ++- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/routes/admin.js diff --git a/src/routes/admin.js b/src/routes/admin.js new file mode 100644 index 0000000..abb320a --- /dev/null +++ b/src/routes/admin.js @@ -0,0 +1,45 @@ +import AdminPage, { loader as adminLoader } from "pages/admin/AdminPage"; +import AnnounceDetailPage from "pages/home/AnnounceDetailPage"; +import AnnouncePage from "pages/home/AnnouncePage"; + +const admin = [ + { + path: "/admin", + element: , + loader: adminLoader, + children: [ + { + index: true, + element: , + }, + { + path: "announce", + element: , + children: [ + { + index: true, + element: , + }, + { + path: "edit/:id", + element: , + }, + ], + }, + { + path: "user-manage", + element: <>유저 관리, + }, + { + path: "report-manage", + element: <>신고 관리, + }, + { + path: "service-center", + element: <>1ㄷ1 문의 관리, + }, + ], + }, +]; + +export default admin; diff --git a/src/routes/root.js b/src/routes/root.js index ad81782..5b86c34 100644 --- a/src/routes/root.js +++ b/src/routes/root.js @@ -3,13 +3,14 @@ import { createBrowserRouter } from "react-router-dom"; import auth from "routes/auth"; import home from "routes/home"; import lobby from "routes/lobby"; +import admin from "routes/admin"; const router = createBrowserRouter([ { path: "/", element: , loader: rootLoader, - children: [...auth, ...home, ...lobby], + children: [...auth, ...home, ...lobby, ...admin], }, ]); From 97bc9e1e7883e956f8711d10036a40cf7c804670 Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Tue, 18 Nov 2025 01:01:51 +0900 Subject: [PATCH 05/29] =?UTF-8?q?feat:=20=EA=B3=B5=EC=A7=80=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=EC=9E=90=20=EB=AA=A8=EB=93=9C=EB=A1=9C=20=EB=93=A4=EC=96=B4?= =?UTF-8?q?=EA=B0=94=EC=9D=84=EB=95=8C=EC=9D=98=20=EB=8F=99=EC=9E=91=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/admin/AdminPage.jsx | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/pages/admin/AdminPage.jsx diff --git a/src/pages/admin/AdminPage.jsx b/src/pages/admin/AdminPage.jsx new file mode 100644 index 0000000..5bc7c15 --- /dev/null +++ b/src/pages/admin/AdminPage.jsx @@ -0,0 +1,41 @@ +import { AdminHeader } from "components/admin/AdminHeader"; +import ScrollToTop from "components/common/ScrollToTop"; +import { useEffect } from "react"; +import { Outlet } from "react-router-dom"; +import { tokenReissueAPI } from "services/auth/auth"; +import "styles/pages/admin/AdminPage.scss"; +import { getAuthToken } from "utils/token"; + +const AdminPage = () => { + useEffect(() => { + window.scrollTo(0, 0); + }, []); + + return ( +
+ + + +
+ ); +}; + +export default AdminPage; + +export const loader = async () => { + const { accessToken, setAccessToken } = getAuthToken(); + + if (!accessToken) { + // 토큰 재발급 + try { + const res = await tokenReissueAPI(); + const newAccessToken = res.accessToken; + const expireTime = res.expiredAt; + setAccessToken(newAccessToken, expireTime); + } catch (e) { + console.error(e); + return { isSignIn: false }; + } + } + return { isSignIn: true }; +}; From ece4dcc7c17e7a59a39251822f2198fe9991b738 Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Tue, 18 Nov 2025 01:02:38 +0900 Subject: [PATCH 06/29] =?UTF-8?q?feat:=20role=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=9D=BC=20=EC=9D=B4=EB=8F=99=ED=95=A0=20=EC=A3=BC=EC=86=8C=20?= =?UTF-8?q?return=ED=95=98=EB=8A=94=20util=ED=95=A8=EC=88=98=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/user.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/utils/user.js b/src/utils/user.js index 0ecb913..97dff89 100644 --- a/src/utils/user.js +++ b/src/utils/user.js @@ -1,3 +1,5 @@ +import { ADMIN_ANNOUNCE_URL, ANNOUNCE_URL } from "constants/url"; + // src/utils/getUserInfo.js const { default: useUserInformationStore } = require("store/userInformation"); @@ -34,4 +36,7 @@ const getUserName = () => { return nickname; }; -export { getUserInfo, getUserUuid, getUserName }; +const getAnnounceDetailLink = (isAdmin, id) => { + return isAdmin ? `${ADMIN_ANNOUNCE_URL}/${id}` : `${ANNOUNCE_URL}/${id}`; +}; +export { getUserInfo, getUserUuid, getUserName, getAnnounceDetailLink }; From 838a117c7bf95f2b4e40760fcf0ce138609bcd09 Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Tue, 18 Nov 2025 01:31:28 +0900 Subject: [PATCH 07/29] =?UTF-8?q?refactor:=20=EA=B3=B5=EC=A7=80=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=20=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=EC=9E=90=20=EB=AA=A8=EB=93=9C=EC=9E=84?= =?UTF-8?q?=EC=9D=84=20=ED=99=95=EC=9D=B8=ED=95=98=EB=8A=94=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/home/AnnouncePage.jsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/pages/home/AnnouncePage.jsx b/src/pages/home/AnnouncePage.jsx index 82252a5..8b769ec 100644 --- a/src/pages/home/AnnouncePage.jsx +++ b/src/pages/home/AnnouncePage.jsx @@ -7,6 +7,8 @@ import Pagination from "commons/ui/Pagination"; import { getAnnounceListAPI } from "services/home/announce"; import { EmptyContent } from "commons/emptyContent/EmptyContent"; import AnnounceSortButtons from "commons/ui/button/AnnounceSortButton"; +import useUserInformationStore from "store/userInformation"; +import { getAnnounceDetailLink } from "utils/user"; const getTabClassName = (tabName, currentTab) => { const classes = ["tab"]; @@ -28,6 +30,10 @@ const AnnouncePage = () => { const currentPage = Number(searchParams.get("page")) || 1; const sortOrder = searchParams.get("sort") || "DATE_DESC"; + const profile = useUserInformationStore((state) => state.profile); + const isAdmin = + profile?.role === "ADMIN" && window.location.href.includes("admin"); + /** 공지사항 API 호출 */ const fetchNotices = async (page = 1, sort = "DATE_DESC") => { try { @@ -122,7 +128,10 @@ const AnnouncePage = () => { key={`notice-${notice.notificationId}`} className="announce-item" > - + {notice.title}
From 9d787925771c5531140d42c26fa7a2e1fcf24218 Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Tue, 18 Nov 2025 01:58:49 +0900 Subject: [PATCH 08/29] =?UTF-8?q?design:=20=EA=B3=B5=EC=A7=80=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=88=98=EC=A0=95=20=EC=82=AD=EC=A0=9C=20=EB=B0=94?= =?UTF-8?q?=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/admin/AnnounceManageBar.scss | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/styles/components/admin/AnnounceManageBar.scss diff --git a/src/styles/components/admin/AnnounceManageBar.scss b/src/styles/components/admin/AnnounceManageBar.scss new file mode 100644 index 0000000..6c78b64 --- /dev/null +++ b/src/styles/components/admin/AnnounceManageBar.scss @@ -0,0 +1,42 @@ +.announce-manage-button-bar { + display: flex; + align-items: center; + gap: 138px; + a { + text-decoration: none; + } + .button--edit { + padding: 8px 16px; + height: 40px; + width: 194px; + border: none; + border-radius: 4px; + color: #fff; + cursor: pointer; + font-size: 14px; + font-weight: 600; + line-height: 1; + display: inline-flex; + align-items: center; + justify-content: center; + background: #F28110; + } + + .button--delete { + width: 194px; + padding: 8px 16px; + height: 40px; + border: none; + border-radius: 4px; + color: #fff; + cursor: pointer; + font-size: 14px; + font-weight: 600; + line-height: 1; + display: inline-flex; + align-items: center; + justify-content: center; + background: #808080; + } + +} \ No newline at end of file From e1a1ebbf5ecb08c9c7e67411879668e365fa7dde Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Tue, 18 Nov 2025 01:59:32 +0900 Subject: [PATCH 09/29] =?UTF-8?q?refactor:=20=EA=B4=80=EB=A6=AC=EC=9E=90?= =?UTF-8?q?=20=EC=9E=85=EC=9E=A5=20=EB=B2=84=ED=8A=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/home/EnterAdmin.jsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/home/EnterAdmin.jsx b/src/components/home/EnterAdmin.jsx index 9c9296f..ff6948c 100644 --- a/src/components/home/EnterAdmin.jsx +++ b/src/components/home/EnterAdmin.jsx @@ -1,4 +1,5 @@ import { AdminButton } from "commons/svgs/AdminButton"; +import { ADMIN_URL } from "constants/url"; import React from "react"; import { useNavigate } from "react-router-dom"; import "styles/components/home/EnterAdmin.scss"; @@ -7,7 +8,7 @@ export default function EnterAdmin() { const navigate = useNavigate(); const handleClick = () => { - navigate("/admin"); + navigate(ADMIN_URL); }; const handleKeyDown = (e) => { @@ -23,8 +24,6 @@ export default function EnterAdmin() { type="button" onClick={handleClick} onKeyDown={handleKeyDown} - aria-label="관리자 페이지로 이동" - title="관리자 페이지로 이동" > From 52fca7faa3ba57dfe864082a9ce6536dfd89d6a2 Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Tue, 18 Nov 2025 02:00:08 +0900 Subject: [PATCH 10/29] =?UTF-8?q?refactor:=20=EA=B8=B0=EC=A1=B4=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=9E=AC=ED=99=9C=EC=9A=A9=20?= =?UTF-8?q?=EC=96=B4=EB=93=9C=EB=AF=BC=20=EB=8F=99=EC=9E=91=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/home/AnnounceDetailPage.jsx | 7 +++++++ src/pages/home/AnnouncePage.jsx | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/pages/home/AnnounceDetailPage.jsx b/src/pages/home/AnnounceDetailPage.jsx index b26bd5c..25ae806 100644 --- a/src/pages/home/AnnounceDetailPage.jsx +++ b/src/pages/home/AnnounceDetailPage.jsx @@ -5,6 +5,8 @@ import "styles/pages/home/AnnounceDetailPage.scss"; import { formatDate } from "utils/time"; import { useEffect, useState } from "react"; import { getAnnounceDetailAPI } from "services/home/announce"; +import useUserInformationStore from "store/userInformation"; +import { AnnounceManageBar } from "components/admin/AnnounceManageBar"; /** 공통 상태 컴포넌트 */ const AnnounceStatus = ({ type, message }) => ( @@ -20,6 +22,10 @@ const AnnounceDetailPage = () => { const [notice, setNotice] = useState(null); const [status, setStatus] = useState({ loading: true, error: null }); + const profile = useUserInformationStore((state) => state.profile); + const isAdminMode = + profile?.role === "ADMIN" && window.location.href.includes("admin"); + const closeDetailPage = () => navigate(-1); useEffect(() => { @@ -67,6 +73,7 @@ const AnnounceDetailPage = () => { {notice.title}
{notice.content}
+ {isAdminMode && } diff --git a/src/pages/home/AnnouncePage.jsx b/src/pages/home/AnnouncePage.jsx index 8b769ec..646ae1b 100644 --- a/src/pages/home/AnnouncePage.jsx +++ b/src/pages/home/AnnouncePage.jsx @@ -31,7 +31,7 @@ const AnnouncePage = () => { const sortOrder = searchParams.get("sort") || "DATE_DESC"; const profile = useUserInformationStore((state) => state.profile); - const isAdmin = + const isAdminMode = profile?.role === "ADMIN" && window.location.href.includes("admin"); /** 공지사항 API 호출 */ @@ -130,7 +130,7 @@ const AnnouncePage = () => { > {notice.title} From 9d1b1292d7c1c460c77d5b2182e93eb7be808211 Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Tue, 18 Nov 2025 02:35:49 +0900 Subject: [PATCH 11/29] =?UTF-8?q?feat:=20=EA=B3=B5=EC=A7=80=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=82=AD=EC=A0=9C=20api=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/services/admin/admin.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/services/admin/admin.js diff --git a/src/services/admin/admin.js b/src/services/admin/admin.js new file mode 100644 index 0000000..6491613 --- /dev/null +++ b/src/services/admin/admin.js @@ -0,0 +1,12 @@ +import { ADMIN_ANNOUNCE_DELETE_API } from "constants/api"; +import { apiInterface } from "services/axiosForm"; + +export const eraseNotification = async (notificationId) => { + return await apiInterface( + "delete", + `${ADMIN_ANNOUNCE_DELETE_API}/${notificationId}`, + { notificationId }, + {}, + true + ); +}; From be46fa6c10f1fd3f1833daed060970c77116ae90 Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Tue, 18 Nov 2025 03:00:24 +0900 Subject: [PATCH 12/29] =?UTF-8?q?design:=20admin=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/components/admin/AdminHeader.scss | 30 +++++++ src/styles/pages/admin/AdminPage.scss | 9 ++ src/styles/pages/admin/AnnounceEditPage.scss | 93 ++++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 src/styles/components/admin/AdminHeader.scss create mode 100644 src/styles/pages/admin/AdminPage.scss create mode 100644 src/styles/pages/admin/AnnounceEditPage.scss diff --git a/src/styles/components/admin/AdminHeader.scss b/src/styles/components/admin/AdminHeader.scss new file mode 100644 index 0000000..f1b4ac0 --- /dev/null +++ b/src/styles/components/admin/AdminHeader.scss @@ -0,0 +1,30 @@ +.admin-page-header { + position: fixed; + z-index: 100; + display: flex; + align-items: center; + justify-content: center; + gap: 54px; + width: 100%; + height: 20%; + background: white; + img { + width: 366px; + height: 58px; + } + + a { + text-decoration: none; + color: black; + font-size: 14px; + font-family: "SUIT-Regular"; + } + + .admin-page-nav-container { + display: flex; + justify-content: center; + white-space: nowrap; + width: 600px; + gap: 80px; + } +} diff --git a/src/styles/pages/admin/AdminPage.scss b/src/styles/pages/admin/AdminPage.scss new file mode 100644 index 0000000..a654765 --- /dev/null +++ b/src/styles/pages/admin/AdminPage.scss @@ -0,0 +1,9 @@ +.admin-page-container { + position: relative; + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + height: auto; + background-color: white; +} diff --git a/src/styles/pages/admin/AnnounceEditPage.scss b/src/styles/pages/admin/AnnounceEditPage.scss new file mode 100644 index 0000000..5e70254 --- /dev/null +++ b/src/styles/pages/admin/AnnounceEditPage.scss @@ -0,0 +1,93 @@ +.announce-edit-page-container { + position: relative; + width: 1278px; + min-height: 100vh; + padding-top: 186px; + display: flex; + flex-direction: column; + align-items: center; + font-family: SUIT-Regular; + + .announce-edit-container { + width: 1278px; + height: calc(100vh - 244px); + + position: absolute; + top: 244px; + + background: #ffffff; + border-width: 1.5px 1.5px 0 1.5px; + border-style: solid; + border-color: #000; + border-radius: 24px 24px 0 0 ; + box-shadow: 0px 0px 16px rgba(0, 0, 0, 0.25); + + animation: slideUpFade 0.4s ease-out forwards; + + + .announce-edit-header { + position: relative; + + .close-btn { + position: absolute; + right: 35px; + top: 29px; + } + } + + .announce-edit-content { + display: flex; + flex-direction: column; + align-items: center; + padding-top: 120px; + gap: 35px; + + + .content-title { + display: flex; + align-items: center; + gap: 30px; + width: 960px; + + .edit-title-input { + background-color: #F2F3F6; + width: 960px; + height: 44px; + font-size: 20px; + border: 1px solid #ccc; + padding: 0 12px; + text-align: center; + } + } + + .edit-content-input { + background-color: #F2F3F6; + width: 960px; + border: 1px solid #ccc; + padding: 36px 120px; + font-size: 18px; + line-height: 1.4; + text-align: center; + overflow: auto; + } + + .save-button { + margin-top: 16px; + width: 960px; + height: 40px; + border: none; + border-radius: 6px; + font-size: 16px; + font-weight: 700; + background: #FFDA37; + color: black; + cursor: pointer; + transition: 0.2s; + + &:hover { + opacity: 0.9; + } + } + } + } +} From 0810baa1fb9a6d123d6de6d5fe97281911ce5590 Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Tue, 18 Nov 2025 03:01:24 +0900 Subject: [PATCH 13/29] =?UTF-8?q?feat:=20=EA=B3=B5=EC=A7=80=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=88=98=EC=A0=95=20=EC=82=AD=EC=A0=9C=20bar=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/admin/AnnounceManageBar.jsx | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/components/admin/AnnounceManageBar.jsx diff --git a/src/components/admin/AnnounceManageBar.jsx b/src/components/admin/AnnounceManageBar.jsx new file mode 100644 index 0000000..cf218e2 --- /dev/null +++ b/src/components/admin/AnnounceManageBar.jsx @@ -0,0 +1,31 @@ +import { ADMIN_ANNOUNCE_URL } from "constants/url"; +import { Link, useNavigate } from "react-router-dom"; +import { eraseNotification } from "services/admin/admin"; +import "styles/components/admin/AnnounceManageBar.scss"; + +export const AnnounceManageBar = ({ notificationId }) => { + const navigate = useNavigate(); + + const handleDelete = async () => { + try { + await eraseNotification(notificationId); + navigate(-1); + } catch (error) { + console.error("삭제 실패:", error); + } + }; + + return ( +
+ + 수정 + + +
+ ); +}; From c47d12275f3586bd6980fd87f2cbdab6255d8fce Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Tue, 18 Nov 2025 13:47:40 +0900 Subject: [PATCH 14/29] =?UTF-8?q?feat:=20=EA=B3=B5=EC=A7=80=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=88=98=EC=A0=95,=20=EA=B2=8C=EC=8B=9C=20api=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/services/admin/admin.js | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/services/admin/admin.js b/src/services/admin/admin.js index 6491613..d3cc18b 100644 --- a/src/services/admin/admin.js +++ b/src/services/admin/admin.js @@ -1,12 +1,32 @@ -import { ADMIN_ANNOUNCE_DELETE_API } from "constants/api"; +import { ADMIN_ANNOUNCE_MANAGE_API } from "constants/api"; import { apiInterface } from "services/axiosForm"; export const eraseNotification = async (notificationId) => { return await apiInterface( "delete", - `${ADMIN_ANNOUNCE_DELETE_API}/${notificationId}`, + `${ADMIN_ANNOUNCE_MANAGE_API}/${notificationId}`, { notificationId }, {}, true ); }; + +export const updateAnnounceAPI = async (notification) => { + return await apiInterface( + "put", + `${ADMIN_ANNOUNCE_MANAGE_API}/${notification.id}`, + { title: notification.title, content: notification.content }, + {}, + true + ); +}; + +export const postAnnounceAPI = async (notification) => { + return await apiInterface( + "post", + `${ADMIN_ANNOUNCE_MANAGE_API}`, + { title: notification.title, content: notification.content }, + {}, + true + ); +}; From 85e2cec9336b5b9723fdf658eb46abf368c6a53a Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Tue, 18 Nov 2025 13:49:29 +0900 Subject: [PATCH 15/29] =?UTF-8?q?chore:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20ap?= =?UTF-8?q?i=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/api.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/constants/api.js b/src/constants/api.js index 91e3ed5..aa5e88c 100644 --- a/src/constants/api.js +++ b/src/constants/api.js @@ -68,4 +68,10 @@ export const SOCKET_CHAT_ALL_PUB = process.env.REACT_APP_WS_CHAT_ALL_PUB_API; export const SOCKET_CHAT_PRIVATE = process.env.REACT_APP_WS_CHAT_PRIVATE_API; // 공지사항 API -export const ANNOUNCE_LIST_API = process.env.REACT_APP_ANNOUNCE_LIST_API; \ No newline at end of file +export const ANNOUNCE_LIST_API = process.env.REACT_APP_ANNOUNCE_LIST_API; + +// 관리자 API +export const ADMIN_ANNOUNCE_MANAGE_API = + process.env.REACT_APP_ADMIN_ANNOUNCE_MANAGE_API; +export const ADMIN_QNA_MANAGE_API = process.env.ADMIN_QNA_MANAGE_API; +export const ADMIN_REPORT_API = process.env.REACT_APP_ADMIN_REPORT_API; From 3a41c06243364955990c3cef56aeaaf78862c457 Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Tue, 18 Nov 2025 13:52:56 +0900 Subject: [PATCH 16/29] =?UTF-8?q?feat:=20=EC=82=AD=EC=A0=9C=20=ED=9B=84=20?= =?UTF-8?q?=EB=92=A4=EB=A1=9C=EA=B0=80=EA=B8=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/admin/AnnounceManageBar.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/admin/AnnounceManageBar.jsx b/src/components/admin/AnnounceManageBar.jsx index cf218e2..0d8f654 100644 --- a/src/components/admin/AnnounceManageBar.jsx +++ b/src/components/admin/AnnounceManageBar.jsx @@ -9,7 +9,7 @@ export const AnnounceManageBar = ({ notificationId }) => { const handleDelete = async () => { try { await eraseNotification(notificationId); - navigate(-1); + navigate(ADMIN_ANNOUNCE_URL); } catch (error) { console.error("삭제 실패:", error); } From 4d3fe64ba478019651170415d062e0d33e40dffb Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Tue, 18 Nov 2025 13:54:32 +0900 Subject: [PATCH 17/29] =?UTF-8?q?refactor:=20=EA=B3=B5=EC=A7=80=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EA=B4=80=EB=A6=AC=EB=B0=94=20props=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/home/AnnounceDetailPage.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/AnnounceDetailPage.jsx b/src/pages/home/AnnounceDetailPage.jsx index 25ae806..66715f7 100644 --- a/src/pages/home/AnnounceDetailPage.jsx +++ b/src/pages/home/AnnounceDetailPage.jsx @@ -73,7 +73,7 @@ const AnnounceDetailPage = () => { {notice.title}
{notice.content}
- {isAdminMode && } + {isAdminMode && } From 0afe12025b08bc7099846304a327ea3f8194c7e5 Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Tue, 18 Nov 2025 13:54:54 +0900 Subject: [PATCH 18/29] =?UTF-8?q?chore:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20ur?= =?UTF-8?q?l=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/url.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/constants/url.js b/src/constants/url.js index cc2257a..22bdd42 100644 --- a/src/constants/url.js +++ b/src/constants/url.js @@ -5,6 +5,9 @@ export const SIGN_UP_URL = "/signup"; // 회원가입 export const ACCOUNT_URL = "/find/account"; // 비밀번호 찾기 export const WITHDRAW_URL = "/withdraw"; // 비밀번호 찾기 +export const ADMIN_URL = "/admin"; +export const ADMIN_ANNOUNCE_URL = "/admin/announce"; + export const LOBBY_URL = "/lobby"; // 로비 export const MY_PAGE_URL = "/lobby/myinfo"; // 마이페이지 export const MY_RECORD_URL = "/lobby/myinfo/record"; // 마이페이지 내 전적 From 7e778ca74d76aa4854671f26c7fffe8d370c8327 Mon Sep 17 00:00:00 2001 From: Hwang gend Date: Tue, 18 Nov 2025 13:55:13 +0900 Subject: [PATCH 19/29] =?UTF-8?q?feat:=20=EA=B3=B5=EC=A7=80=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=88=98=EC=A0=95=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/admin/AnnounceEditPage.jsx | 85 ++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/pages/admin/AnnounceEditPage.jsx diff --git a/src/pages/admin/AnnounceEditPage.jsx b/src/pages/admin/AnnounceEditPage.jsx new file mode 100644 index 0000000..1c70e02 --- /dev/null +++ b/src/pages/admin/AnnounceEditPage.jsx @@ -0,0 +1,85 @@ +import CloseButton from "commons/ui/button/CloseButton"; +import { useNavigate, useParams } from "react-router-dom"; +import "styles/pages/admin/AnnounceEditPage.scss"; +import { useEffect, useState } from "react"; +import { getAnnounceDetailAPI } from "services/home/announce"; +import useUserInformationStore from "store/userInformation"; +import { updateAnnounceAPI } from "services/admin/admin"; + +const AnnounceEditPage = () => { + const navigate = useNavigate(); + const { id } = useParams(); + const [title, setTitle] = useState(""); + const [content, setContent] = useState(""); + const [loading, setLoading] = useState(true); + + const profile = useUserInformationStore((state) => state.profile); + const isAdminMode = + profile?.role === "ADMIN" && window.location.pathname.includes("admin"); + + const closeEditPage = () => navigate(-1); + + useEffect(() => { + const fetchDetail = async () => { + try { + const res = await getAnnounceDetailAPI(id); + setTitle(res.title); + setContent(res.content); + } catch (err) { + alert("공지사항 정보를 불러오지 못했습니다."); + } finally { + setLoading(false); + } + }; + fetchDetail(); + }, [id]); + + const handleSubmit = async () => { + try { + const notificationInfo = { id, title, content }; + await updateAnnounceAPI(notificationInfo); + navigate(`/admin/announce/${id}`); + } catch (err) { + console.log(err); + alert("공지 수정에 실패했습니다."); + } + }; + + if (!isAdminMode) return
권한이 없습니다.
; + if (loading) return
로딩 중...
; + + return ( +
+
+
+ +
+ +
+
+ setTitle(e.target.value)} + placeholder="공지 제목을 입력하세요" + /> +
+ +