Skip to content

Commit

Permalink
Merge pull request #110 from softeerbootcamp4th/feature/30-admin-even…
Browse files Browse the repository at this point in the history
…t-detail

[feat] 어드민 페이지 이벤트 상세보기 페이지 구현
  • Loading branch information
darkdulgi authored Aug 19, 2024
2 parents d1b8b5c + e67a139 commit 2f0c4bf
Show file tree
Hide file tree
Showing 159 changed files with 1,908 additions and 955 deletions.
Binary file added public/font/HyundaiSansTextKROTFRegular.otf
Binary file not shown.
6 changes: 1 addition & 5 deletions src/adminPage/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,7 @@ function App() {
<Routes>
<Route element={<ProtectedRoute />}>
<Route exact path="/events/create" element={<EventsCreatePage />} />
<Route
exact
path="/events/:eventId/edit"
element={<EventsEditPage />}
/>
<Route exact path="/events/:eventId/edit" element={<EventsEditPage />} />
<Route path="/events/:eventId" element={<EventsDetailPage />} />
<Route path="/events" element={<EventsPage />} />
<Route path="/comments/:eventId" element={<CommentsIDPage />} />
Expand Down
24 changes: 8 additions & 16 deletions src/adminPage/features/comment/id/Comments.jsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
import { useQuery } from "@common/dataFetch/getQuery.js";
import { fetchServer } from "@common/dataFetch/fetchServer.js";

export default function Comments({
eventId,
checkedComments,
setCheckedComments,
page,
setAllId,
}) {
export default function Comments({ eventId, checkedComments, setCheckedComments, page, setAllId }) {
const data = useQuery(
eventId,
() =>
fetchServer(
`/api/v1/admin/comments?eventId=${eventId}&page=${page}&size=15`,
).then(({ comments }) => {
setAllId(comments.map((comment) => comment.id));
return comments;
}),
fetchServer(`/api/v1/admin/comments?eventId=${eventId}&page=${page}&size=15`).then(
({ comments }) => {
setAllId(comments.map((comment) => comment.id));
return comments;
},
),
[page],
);

Expand Down Expand Up @@ -64,9 +58,7 @@ export default function Comments({
<div className="place-self-center flex items-center gap-1 text-body-s">
<span>{getDate(comment.createdAt)}</span>

<span className="text-neutral-500">
{getTime(comment.createdAt)}
</span>
<span className="text-neutral-500">{getTime(comment.createdAt)}</span>
</div>

<span className="text-body-s">{comment.content}</span>
Expand Down
10 changes: 2 additions & 8 deletions src/adminPage/features/comment/id/DeleteButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ import { fetchServer } from "@common/dataFetch/fetchServer.js";
import ConfirmModal from "@admin/modals/ConfirmModal.jsx";
import AlertModal from "@admin/modals/AlertModal.jsx";

export default function DeleteButton({
eventId,
checkedComments,
setCheckedComments,
}) {
export default function DeleteButton({ eventId, checkedComments, setCheckedComments }) {
const num = checkedComments.size;
const mutation = useMutation(eventId, () =>
fetchServer("/api/v1/admin/comments", {
Expand All @@ -18,9 +14,7 @@ export default function DeleteButton({
},
})
.then(() => {
openModal(
<AlertModal title="삭제" description="기대평이 삭제되었습니다." />,
);
openModal(<AlertModal title="삭제" description="기대평이 삭제되었습니다." />);
setCheckedComments(new Set());
})
.catch((e) => {
Expand Down
8 changes: 2 additions & 6 deletions src/adminPage/features/comment/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ export default function AdminComment() {
} else if (filteredString.length <= 6) {
setFormString("HD_" + filteredString);
} else if (filteredString.length <= 9) {
setFormString(
"HD_" + filteredString.slice(0, 6) + "_" + filteredString.slice(6),
);
setFormString("HD_" + filteredString.slice(0, 6) + "_" + filteredString.slice(6));
} else return;

if (filteredString.length >= 6) {
Expand Down Expand Up @@ -73,9 +71,7 @@ export default function AdminComment() {
</li>
))}

<span
className={`${searchList.length && "hidden"} text-neutral-300 text-body-s`}
>
<span className={`${searchList.length && "hidden"} text-neutral-300 text-body-s`}>
일치하는 검색 결과가 없습니다.
</span>
</div>
Expand Down
9 changes: 2 additions & 7 deletions src/adminPage/features/comment/mock.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { http, HttpResponse } from "msw";
import getRandomString from "@common/mock/getRandomString";


function getSampleEventList() {
const len = 10;
let eventList = [];
Expand Down Expand Up @@ -35,12 +34,8 @@ function getSampleCommentList() {
}

const handlers = [
http.get("/api/v1/admin/events/hints", () =>
HttpResponse.json(getSampleEventList()),
),
http.get("/api/v1/admin/comments", () =>
HttpResponse.json(getSampleCommentList()),
),
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)),
];

Expand Down
59 changes: 59 additions & 0 deletions src/adminPage/features/eventDetail/EventBaseDataRenderer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import tableStyle from "./tableStyle.js";
import EventStatus from "@admin/serverTime/EventStatus.js";
import DrawButtonHolder from "./drawButton/DrawButtonHolder.jsx";
import Suspense from "@common/components/Suspense.jsx";
import ErrorBoundary from "@common/components/ErrorBoundary.jsx";
import { formatDate } from "@common/utils.js";

function EventBaseDataRenderer({
name,
eventId,
eventFrameId,
startTime,
endTime,
description,
url,
eventType,
}) {
return (
<div className={tableStyle}>
<p className="text-center font-bold">이벤트 명</p>
<p className="font-medium">{name}</p>
<p className="text-center font-bold">이벤트 ID</p>
<p className="font-medium">{eventId}</p>
<p className="text-center font-bold">이벤트 프레임</p>
<p>{eventFrameId}</p>
<p className="text-center font-bold">이벤트 기간</p>
<div>
{formatDate(startTime, "YYYY-MM-DD hh:mm")} ~ {formatDate(endTime, "YYYY-MM-DD hh:mm")} (
<span className="font-medium">
<EventStatus startTime={startTime} endTime={endTime} />
</span>
)
</div>
<p className="text-center font-bold self-start h-8 flex justify-center items-center">
이벤트 요약
</p>
<div className="relative">{description}</div>
<p className="text-center font-bold">이벤트 URL</p>
<p>
<a href={url} className="text-blue-800 hover:underline active:underline">
{url}
</a>
</p>
<p className="text-center font-bold">이벤트 종류</p>
<div className="flex flex-wrap justify-between items-center">
<p className="font-medium">{eventType === "fcfs" ? "선착순" : "추첨"}</p>
{eventType === "draw" && (
<ErrorBoundary fallback={"error"}>
<Suspense fallback={"suspense"}>
<DrawButtonHolder endTime={endTime} />
</Suspense>
</ErrorBoundary>
)}
</div>
</div>
);
}

export default EventBaseDataRenderer;
12 changes: 12 additions & 0 deletions src/adminPage/features/eventDetail/EventDetailFetcher.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import EventDetail from "./index.jsx";
import { useQuery } from "@common/dataFetch/getQuery.js";
import { fetchServer } from "@common/dataFetch/fetchServer.js";

function EventDetailFetcher({ eventId }) {
const data = useQuery(`event-detail-${eventId}`, () =>
fetchServer(`/api/v1/admin/events/${eventId}`),
);
return <EventDetail data={data} />;
}

export default EventDetailFetcher;
11 changes: 11 additions & 0 deletions src/adminPage/features/eventDetail/draw/EventDrawMetadataItem.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function EventDrawMetadataItem({ grade, count, prizeInfo }) {
return (
<>
<p className="font-medium">{grade}</p>
<p>{count}</p>
<p className="justify-self-start">{prizeInfo}</p>
</>
);
}

export default EventDrawMetadataItem;
12 changes: 12 additions & 0 deletions src/adminPage/features/eventDetail/draw/EventDrawPolicyItem.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { POLICY_ENUM } from "@admin/constants.js";

function EventDrawPolicyItem({ action, score }) {
return (
<>
<p className="justify-self-start">{POLICY_ENUM[action]}</p>
<p>{score}</p>
</>
);
}

export default EventDrawPolicyItem;
45 changes: 45 additions & 0 deletions src/adminPage/features/eventDetail/draw/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import EventDrawMetadataItem from "./EventDrawMetadataItem.jsx";
import EventDrawPolicyItem from "./EventDrawPolicyItem.jsx";
import tableStyle from "../tableStyle.js";

function EventDrawDataRenderer({ data }) {
const gridCommonStyle = "grid px-2 gap-4 justify-items-center";
const metadataGridStyle = `${gridCommonStyle} grid-cols-[3rem_6rem_1fr]`;
const policyGridStyle = `${gridCommonStyle} grid-cols-[3fr_1fr]`;
const headerStyle = `h-10 bg-neutral-50 rounded-lg text-black items-center font-bold text-center
*:relative *:w-full *:after:h-full *:after:absolute *:after:-right-2 *:after:border-r *:after:border-neutral-200`;
const titleStyle = "text-center font-bold self-start h-10 flex justify-center items-center";
return (
<>
<section className={`${tableStyle} gap-y-6`}>
<p className={titleStyle}>당첨 인원수</p>
<div className="flex flex-col gap-2">
<div className={`${metadataGridStyle} ${headerStyle}`}>
<p>등수</p>
<p>인원 수</p>
<p className="last:after:border-r-0">경품</p>
</div>
<div className={`${metadataGridStyle} gap-y-2 font-regular`}>
{data.metadata.map((data) => (
<EventDrawMetadataItem key={data.id} {...data} />
))}
</div>
</div>
<p className={titleStyle}>점수 정책</p>
<div className="flex flex-col gap-2">
<div className={`${policyGridStyle} ${headerStyle}`}>
<p>액션</p>
<p className="last:after:border-r-0">배율</p>
</div>
<div className={`${policyGridStyle} gap-y-2 font-regular`}>
{data.policies.map((data) => (
<EventDrawPolicyItem key={data.id} {...data} />
))}
</div>
</div>
</section>
</>
);
}

export default EventDrawDataRenderer;
66 changes: 66 additions & 0 deletions src/adminPage/features/eventDetail/drawButton/DrawButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { useParams } from "react-router-dom";
import { fetchServer } from "@common/dataFetch/fetchServer.js";
import { useQuery, useMutation } from "@common/dataFetch/getQuery.js";
import Button from "@common/components/Button.jsx";
import openModal from "@common/modal/openModal.js";

import AlertModal from "@admin/modals/AlertModal.jsx";

import DrawResultModal from "./DrawResultModal.jsx";
import ErrorBoundary from "@common/components/ErrorBoundary.jsx";
import Suspense from "@common/components/Suspense.jsx";
import Spinner from "@common/components/Spinner.jsx";
import DelaySkeleton from "@common/components/DelaySkeleton.jsx";

function DrawButton() {
const { eventId } = useParams();
const drawResultData = useQuery(
`event-detail-draw-result-${eventId}`,
() => {
return fetchServer(`/api/v1/admin/draw/${eventId}/winners`);
},
{ deferred: true },
);

const resultModal = (
<div className="w-[calc(100vw-8rem)] h-[calc(100vh-8rem)] p-8 bg-white relative">
<ErrorBoundary fallback={<div>에러남</div>}>
<Suspense
fallback={
<div className="w-full h-full flex justify-center items-center">
<DelaySkeleton>
<Spinner />
</DelaySkeleton>
</div>
}
>
<DrawResultModal eventId={eventId} />
</Suspense>
</ErrorBoundary>
</div>
);

const mutate = useMutation(
`event-detail-draw-result-${eventId}`,
() => fetchServer(`/api/v1/admin/draw/${eventId}/draw`, { method: "post" }),
{
onSuccess: () => openModal(resultModal),
onFail: () =>
openModal(<AlertModal title="오류" description="추첨에 오류가 발생했습니다." />),
},
);

if (drawResultData.length === 0)
return (
<Button className="w-32 h-8 px-4 py-1" onClick={mutate}>
추첨하기
</Button>
);
return (
<Button className="w-32 h-8 px-4 py-1" onClick={() => openModal(resultModal)}>
결과 보기
</Button>
);
}

export default DrawButton;
12 changes: 12 additions & 0 deletions src/adminPage/features/eventDetail/drawButton/DrawButtonHolder.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import useServerTimeStore from "@admin/serverTime/store.js";
import DrawButton from "./DrawButton.jsx";

function DrawButtonHolder({ endTime }) {
const getServerTime = useServerTimeStore((store) => store.getData);
const serverTime = getServerTime();

if (new Date(endTime) < serverTime) return <DrawButton />;
return null;
}

export default DrawButtonHolder;
Loading

0 comments on commit 2f0c4bf

Please sign in to comment.