diff --git a/src/adminPage/App.jsx b/src/adminPage/App.jsx index 94aca487..9345f7f7 100644 --- a/src/adminPage/App.jsx +++ b/src/adminPage/App.jsx @@ -7,6 +7,7 @@ import EventsCreatePage from "./pages/EventsCreatePage.jsx"; import ProtectedRoute from "./pages/ProtectedRoute.jsx"; import RootRoute from "./pages/RootRoute.jsx"; import CommentsPage from "./pages/CommentsPage.jsx"; +import CommentsIDPage from "./pages/CommentsIDPage.jsx"; import ServerTimeInitializer from "./shared/serverTime/ServerTimeInitializer.jsx"; import Modal from "@common/modal/modal.jsx"; @@ -31,7 +32,7 @@ function App() { /> } /> } /> - 기대평 화면} /> + } /> } /> } /> diff --git a/src/adminPage/features/comment/id/Comments.jsx b/src/adminPage/features/comment/id/Comments.jsx new file mode 100644 index 00000000..804b48ca --- /dev/null +++ b/src/adminPage/features/comment/id/Comments.jsx @@ -0,0 +1,50 @@ +import { useQuery } from "@common/dataFetch/getQuery.js"; +import { fetchServer } from "@common/dataFetch/fetchServer.js"; + +export default function Comments({ + eventId, + checkedComments, + setCheckedComments, +}) { + const data = useQuery(eventId, () => + fetchServer( + `/api/v1/admin/comments?eventId=${eventId}&page=${0}&size=15`, + ).then((res) => res.comments), + ); + + function onChangeCheckbox(e, id) { + if (e.target.checked) { + setCheckedComments((oldSet) => new Set([...oldSet, id])); + } else { + setCheckedComments((oldSet) => { + const newSet = new Set(oldSet); + newSet.delete(id); + return newSet; + }); + } + } + + return ( +
+ {data.map((comment) => ( +
+ onChangeCheckbox(e, comment.id)} + className="w-4 h-4 place-self-center" + /> + + + {comment.createdAt} + + + {comment.content} +
+ ))} +
+ ); +} diff --git a/src/adminPage/features/comment/id/Loading.jsx b/src/adminPage/features/comment/id/Loading.jsx new file mode 100644 index 00000000..05bcd500 --- /dev/null +++ b/src/adminPage/features/comment/id/Loading.jsx @@ -0,0 +1,9 @@ +import Spinner from "@common/components/Spinner"; + +export default function Loading() { + return ( +
+ +
+ ); +} diff --git a/src/adminPage/features/comment/id/index.jsx b/src/adminPage/features/comment/id/index.jsx new file mode 100644 index 00000000..4607a8ab --- /dev/null +++ b/src/adminPage/features/comment/id/index.jsx @@ -0,0 +1,73 @@ +import Suspense from "@common/components/Suspense"; +import Loading from "./Loading.jsx"; +import Comments from "./Comments.jsx"; +import { useState } from "react"; +import { fetchServer } from "@common/dataFetch/fetchServer.js"; + +export default function AdminCommentID({ eventId }) { + const [checkedComments, setCheckedComments] = useState(new Set()); + + function deleteComments() { + const num = checkedComments.size; + if (!num) return; + + fetchServer("/api/v1/admin/comments", { + method: "DELETE", + body: { + commentIds: [...checkedComments], + }, + }) + .then(() => { + alert(num + "개의 기대평 삭제 완료."); + setCheckedComments(new Set()); + }) + .catch((e) => { + console.log(e); + }); + } + + function searchComment(e) { + e.preventDefault(); + console.log(e.target.searchText.value + "검색"); + } + + return ( +
+ + +
+ + + 검색 +
+ +
+ 선택 + 작성 시간 + 기대평 내용 +
+ + }> + + +
+ ); +} diff --git a/src/adminPage/features/comment/index.jsx b/src/adminPage/features/comment/index.jsx new file mode 100644 index 00000000..c8282b47 --- /dev/null +++ b/src/adminPage/features/comment/index.jsx @@ -0,0 +1,91 @@ +import { useState } from "react"; +import { fetchServer } from "@common/dataFetch/fetchServer"; +import { useNavigate } from "react-router-dom"; + +export default function AdminComment() { + const navigate = useNavigate(); + const [formString, setFormString] = useState(""); + const [isSpread, setIsSpread] = useState(false); + const [searchList, setSearchList] = useState([]); + + function autoCorrect() { + fetchServer(`/api/v1/admin/events/hints?search=${formString}`) + .then((res) => { + setSearchList(res); + setIsSpread(true); + }) + .catch((e) => { + console.log(e); + }); + } + + function onChangeForm(e) { + const filteredString = e.target.value.replace(/[^0-9]/g, ""); + + if (!filteredString) { + setFormString(""); + } else if (filteredString.length <= 6) { + setFormString("HD_" + filteredString); + } else if (filteredString.length <= 9) { + setFormString( + "HD_" + filteredString.slice(0, 6) + "_" + filteredString.slice(6), + ); + } else return; + + if (filteredString.length >= 6) { + autoCorrect(); + } else setIsSpread(false); + } + + function searchEvent(e, eventId) { + e.preventDefault(); + + const eventIDRegex = /^HD_\d{6}_\d{3}$/; + const searchID = eventId ? eventId : formString; + + if (eventIDRegex.test(searchID)) { + navigate(`/comments/${searchID}`); + } + } + + return ( +
+ + +
+ {searchList.map((evt) => ( +
  • searchEvent(e, evt.eventId)} + className={`cursor-pointer list-none w-full rounded px-1 flex hover:bg-blue-200`} + > + {evt.eventId} + {evt.name} +
  • + ))} + + + 일치하는 검색 결과가 없습니다. + +
    + + 검색 +
    + ); +} diff --git a/src/adminPage/features/comment/mock.js b/src/adminPage/features/comment/mock.js new file mode 100644 index 00000000..b70955f0 --- /dev/null +++ b/src/adminPage/features/comment/mock.js @@ -0,0 +1,62 @@ +import { http, HttpResponse } from "msw"; + +function getRandomString(len) { + // const startCode = 0xac00; + // const endCode = 0xd7a3; + + const startCode = 0x0750; + const endCode = 0x077f; + + let str = ""; + for (let i = 0; i < len; i++) { + const randomCode = + Math.floor(Math.random() * (endCode - startCode + 1)) + startCode; + str += String.fromCharCode(randomCode); + } + + return str; +} + +function getSampleEventList() { + const len = 10; + let eventList = []; + for (let i = 0; i < len; i++) { + eventList = [ + ...eventList, + { + eventId: "HD_240909_00" + i, + name: getRandomString(10), + }, + ]; + } + return eventList; +} + +function getSampleCommentList() { + const len = 15; + let commentList = []; + for (let i = 0; i < len; i++) { + commentList = [ + ...commentList, + { + id: i, + content: getRandomString(50), + userName: getRandomString(5), + createdAt: "2024-08-14T07:11:27.244Z", + }, + ]; + } + return { comments: commentList }; +} + +const handlers = [ + http.get("/api/v1/admin/events/hints", () => + HttpResponse.json(getSampleEventList()), + ), + http.get("/api/v1/admin/comments", () => + HttpResponse.json(getSampleCommentList()), + ), + http.delete("/api/v1/admin/comments", () => HttpResponse.json(true)), +]; + +export default handlers; diff --git a/src/adminPage/mock.js b/src/adminPage/mock.js index 58928ebc..35538303 100644 --- a/src/adminPage/mock.js +++ b/src/adminPage/mock.js @@ -1,5 +1,6 @@ import { setupWorker } from "msw/browser"; import authHandler from "@admin/auth/mock.js"; +import commentHandler from "./features/comment/mock.js"; import serverTimeHandler from "@admin/serverTime/mock.js"; import eventSearchHandler from "./features/eventList/mock.js"; @@ -10,4 +11,5 @@ export default setupWorker( ...authHandler, ...eventSearchHandler, ...serverTimeHandler, + ...commentHandler, ); diff --git a/src/adminPage/pages/CommentsIDPage.jsx b/src/adminPage/pages/CommentsIDPage.jsx new file mode 100644 index 00000000..b3a9c69d --- /dev/null +++ b/src/adminPage/pages/CommentsIDPage.jsx @@ -0,0 +1,17 @@ +import Container from "@admin/components/Container.jsx"; +import AdminCommentID from "../features/comment/id"; +import { useParams } from "react-router-dom"; + +export default function CommentsPage() { + const { eventId } = useParams(); + + return ( + +
    + 기대평 + + +
    +
    + ); +} diff --git a/src/adminPage/pages/CommentsPage.jsx b/src/adminPage/pages/CommentsPage.jsx index ecb4dd3b..28f980db 100644 --- a/src/adminPage/pages/CommentsPage.jsx +++ b/src/adminPage/pages/CommentsPage.jsx @@ -1,78 +1,13 @@ import Container from "@admin/components/Container.jsx"; -import { useState } from "react"; +import AdminComment from "../features/comment"; export default function CommentsPage() { - const [formString, setFormString] = useState(""); - const [isSpread, setIsSpread] = useState(false); - const searchList = [ - { - id: "HD_2409_01", - name: "이벤트", - }, - { - id: "HD_2409_02", - name: "이벤트", - }, - { - id: "HD_2409_03", - name: "이벤트", - }, - ]; - - function onChangeForm(e) { - const inputString = e.target.value; - const numberRegex = /^\d*$/; - - if (inputString.length <= 6 && numberRegex.test(inputString)) { - setFormString(inputString); - } - } - - function searchComment(e, eventId) { - e.preventDefault(); - - if (eventId) console.log(eventId + " 검색"); - else console.log(formString + " 검색"); - } - return ( -
    - 기대평 - -
    - setIsSpread(true)} - onBlur={() => setIsSpread(false)} - value={formString} - placeholder="ID (숫자 6자리)" - className={`outline outline-1 outline-neutral-500 px-4 py-2 w-full ${isSpread ? "rounded-t-md" : "rounded-md"}`} - /> - -
    - {searchList.map((evt) => ( -
  • - {evt.id} - {evt.name} -
  • - ))} -
    +
    + 기대평 - 검색 - +
    );