Skip to content

Commit

Permalink
Merge pull request #127 from softeerbootcamp4th/feature/122-admin-user
Browse files Browse the repository at this point in the history
[feat] 어드민 유저 조회 페이지 구현
  • Loading branch information
lybell-art authored Aug 21, 2024
2 parents 753dffc + 1ec1a6f commit 38b3877
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 17 deletions.
2 changes: 2 additions & 0 deletions src/adminPage/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ 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 UsersPage from "./pages/UsersPage.jsx";
import ServerTimeInitializer from "./shared/serverTime/ServerTimeInitializer.jsx";

import Modal from "@common/modal/modal.jsx";
Expand All @@ -31,6 +32,7 @@ function App() {
<Route path="/events" element={<EventsPage />} />
<Route path="/comments/:eventId" element={<CommentsIDPage />} />
<Route path="/comments" element={<CommentsPage />} />
<Route path="/users" element={<UsersPage />} />
</Route>
<Route path="/login" element={<LoginPage />} />
<Route path="/" element={<RootRoute />} />
Expand Down
29 changes: 13 additions & 16 deletions src/adminPage/features/comment/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,37 +20,34 @@ export default function AdminComment() {
}

function onChangeForm(e) {
let newString = e.target.value.replace(/[^0-9]/g, "");
const newString = e.target.value.replace(/[^0-9]/g, "");
const filteredFormString = formString.replace(/[^0-9]/g, "");

if (!newString) {
newString = "";
} else if (newString.length <= 6) {
newString = "HD_" + newString;
} else if (newString.length <= 9) {
newString = "HD_" + newString.slice(0, 6) + "_" + newString.slice(6);
} else return;
if (newString.length > 9) return;

if (newString !== formString) {
if (newString.length >= 9) {
if (newString !== filteredFormString) {
if (newString.length >= 6) {
setSelectedEvent(-1);
setIsSpread(true);
autoCorrect(newString);
} else {
setIsSpread(false);
}
}
setFormString(newString);
if (!newString) {
setFormString("");
} else if (newString.length <= 6) {
setFormString("HD_" + newString);
} else {
setFormString("HD_" + newString.slice(0, 6) + "_" + newString.slice(6));
}
}

function searchEvent(e, eventId) {
e.preventDefault();

const eventIDRegex = /^HD_\d{6}_\d{3}$/;
const searchID = eventId ?? formString;

if (eventIDRegex.test(searchID)) {
navigate(`/comments/${searchID}`);
}
navigate(`/comments/${searchID}`);
}

function onKeyDown(e) {
Expand Down
9 changes: 9 additions & 0 deletions src/adminPage/features/users/Loading.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Spinner from "@common/components/Spinner";

export default function Loading() {
return (
<div className="flex justify-center items-center w-full h-[600px] bg-slate-50">
<Spinner />
</div>
);
}
39 changes: 39 additions & 0 deletions src/adminPage/features/users/Users.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useQuery } from "@common/dataFetch/getQuery.js";
import { fetchServer } from "@common/dataFetch/fetchServer.js";
import Pagination from "@admin/components/Pagination";
import { useState } from "react";

export default function Comments({ searchString, category }) {
searchString;
const [page, setPage] = useState(1);
const data = useQuery(
"admin-users",
() =>
fetchServer(`/api/v1/admin/event-users?page=${page - 1}&search=${searchString}&size=15`)
.then((res) => {
console.log(category);
return res;
})
.catch((e) => {
console.log(e);
}),
[page, searchString],
);

return (
<div className="mt-1 mb-5 flex flex-col items-center gap-1 w-full">
{data.users.map((user) => (
<div
key={user.id}
className="w-full py-1 grid grid-cols-[1fr_1fr_2fr] bg-neutral-50 items-center hover:bg-blue-100 text-body-s place-items-center"
>
<span>{user.userName}</span>
<span>{user.phoneNumber}</span>
<span>{user.frameId}</span>
</div>
))}

<Pagination currentPage={page} setPage={setPage} maxPage={data.totalPage} />
</div>
);
}
65 changes: 65 additions & 0 deletions src/adminPage/features/users/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import Suspense from "@common/components/Suspense";
import Loading from "./Loading.jsx";
import Users from "./Users.jsx";
import { useState } from "react";

export default function AdminCommentID() {
const [formString, setFormString] = useState("");
const [searchString, setSearchString] = useState("");
const [category, setCategory] = useState("name");

function searchComment(e) {
e.preventDefault();
setSearchString(formString);
}

return (
<div className="relative flex flex-col w-full items-center">
<div
className={`absolute -top-6 flex gap-1 text-body-s self-start ${!searchString && "hidden"}`}
>
<span className={`pl-1 text-red-500`}>검색 문자열:</span>
<span className={`text-red-500 italic`}>{searchString}</span>
</div>

<form onSubmit={searchComment} className="w-full relative">
<input
type="text"
value={formString}
onChange={(e) => setFormString(e.target.value)}
placeholder="유저 성명 검색"
className="bg-neutral-50 focus:bg-white w-full px-4 py-2 rounded-lg text-body-s"
/>

<div className="absolute top-1/2 -translate-y-1/2 right-4 flex gap-3">
<select
value={category}
onChange={(e) => setCategory(e.target.value)}
className="bg-transparent text-neutral-600"
>
<option value="name">성명</option>
<option value="phoneNumber">전화번호</option>
<option value="frameId">FrameId</option>
</select>

<img
onClick={searchComment}
src="/icons/search.png"
alt="검색"
className="cursor-pointer "
/>
</div>
</form>

<div className="mt-3 py-1 w-full grid grid-cols-[1fr_1fr_2fr] bg-blue-50 place-items-center text-body-s select-none">
<span>성명</span>
<span>전화번호</span>
<span>이벤트 frameId</span>
</div>

<Suspense fallback={<Loading />}>
<Users searchString={searchString} category={category} />
</Suspense>
</div>
);
}
23 changes: 23 additions & 0 deletions src/adminPage/features/users/mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { http, HttpResponse } from "msw";
import getRandomString from "@common/mock/getRandomString";

function getRandomUsers() {
let users = [];
const num = 15;
for (let i = 0; i < num; i++) {
users = [
...users,
{
id: i,
userName: getRandomString(3),
phoneNumber: "010-0000-0000",
frameId: "event-test",
},
];
}
return { users: users, totalPage: 15 };
}

const handlers = [http.get("/api/v1/admin/event-users", () => HttpResponse.json(getRandomUsers()))];

export default handlers;
2 changes: 2 additions & 0 deletions src/adminPage/mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import serverTimeHandler from "@admin/serverTime/mock.js";
import eventSearchHandler from "./features/eventList/mock.js";
import eventCreateHandler from "./features/eventEdit/mock.js";
import drawHandler from "./features/eventDetail/drawButton/mock.js";
import usersHandler from "./features/users/mock.js";

// mocking은 기본적으로 각 feature 폴더 내의 mock.js로 정의합니다.
// 새로운 feature의 mocking을 추가하셨으면, mock.js의 setupWorker 내부 함수에 인자를 spread 연산자를 이용해 추가해주세요.
Expand All @@ -16,4 +17,5 @@ export default setupWorker(
...commentHandler,
...eventCreateHandler,
...drawHandler,
...usersHandler,
);
16 changes: 16 additions & 0 deletions src/adminPage/pages/UsersPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Container from "@admin/components/Container.jsx";
import Users from "../features/users";

function UsersPage() {
return (
<Container>
<div className="flex flex-col w-full p-20">
<span className="text-title-l pb-10">유저 조회</span>

<Users />
</div>
</Container>
);
}

export default UsersPage;
6 changes: 6 additions & 0 deletions src/adminPage/shared/components/NavBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,15 @@ function NavBar() {
<NavBarItem disabled={!isLogin} to="/events">
events
</NavBarItem>

<NavBarItem disabled={!isLogin} to="/comments">
기대평
</NavBarItem>

<NavBarItem disabled={!isLogin} to="/users">
유저
</NavBarItem>

{isLogin && <NavBarItem onClick={onLogoutClick}>LOGOUT</NavBarItem>}
</ul>
</nav>
Expand Down
2 changes: 1 addition & 1 deletion src/common/constants.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const EVENT_FCFS_ID = "HD_240808_002";
export const EVENT_FCFS_ID = "HD240821_001";
export const EVENT_DRAW_ID = "HD_240808_001";
export const EVENT_ID = "the-new-ioniq5";
export const EVENT_START_DATE = new Date(2024, 8, 9);
Expand Down

0 comments on commit 38b3877

Please sign in to comment.