Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] 어드민 이벤트 생성/수정 기능 구현 (resolve #29) #109

Merged
35 commits merged into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
256c9de
[feat] 오픈시간/종료시간 일괄 설정 폼 추가
lybell-art Aug 16, 2024
b88fc28
[refactor] context api를 이용해 이벤트 등록 리듀서 상태 관리하도록 변경
lybell-art Aug 16, 2024
1103c91
[fix] 일괄설정 폼 변경 시 실제 채워진 선착순 이벤트에 반영이 안 되는 버그 수정
lybell-art Aug 16, 2024
4176d03
[fix] 선착순 각 아이템 시간 조작 시 부적절한 값이 들어갈 수 있는 버그 수정
lybell-art Aug 17, 2024
3ddf30c
[fix] fcfsdata 명세에 맞게 리듀서도 수정
lybell-art Aug 17, 2024
de454ba
[fix] 선착순 이벤트 등록 시 일괄설정 변경시 자연스럽게 바뀌도록 변경
lybell-art Aug 17, 2024
3d912a4
[fix] 이벤트 끝 기간 디폴트값 오후 11시 55분으로 설정
lybell-art Aug 17, 2024
504ed68
[feat] 선착순 입력 인풋 추가
lybell-art Aug 17, 2024
b68fda8
[design] 이벤트 생성 페이지 선착순 테이블 스타일 추가
lybell-art Aug 17, 2024
075b142
[feat] 이벤트 생성 선착순 날짜 선택 추가
lybell-art Aug 17, 2024
ef3a898
[feat] 이벤트 등록 선착순 아이템 삭제 기능 추가
lybell-art Aug 17, 2024
118b187
[fix] 선착순 이벤트 시간 required로 변경
lybell-art Aug 17, 2024
c004836
[feat] 이벤트 등록-선착순 날짜 사용자 입력 날짜 기준을 로컬 시간으로 변경
lybell-art Aug 17, 2024
48cb33b
[fix] 이벤트 등록-선착순이 아무것도 없으면 등록 못하게 변경
lybell-art Aug 17, 2024
9b22f1d
[fix] 버튼 내부 아이콘 전부 드래그 불가능하게 변경
lybell-art Aug 17, 2024
fc0f75a
[chore] 컨플릭트 수정
lybell-art Aug 17, 2024
ea9dd05
[fix] 대부분의 브라우저 환경에서 주행거리 텍스트의 정답을 맞힐 수 없는 버그 수정
lybell-art Aug 17, 2024
ab586da
[fix] feathServer 함수가 서버 응답으로 빈 문자열이 왔을 때 오류를 뿜는 버그 수정
lybell-art Aug 17, 2024
715c9a7
[feat] 추첨 이벤트 등록 기본 폼 레이아웃 추가
lybell-art Aug 17, 2024
696855d
[design] 기본 폰트 regular로 변경
lybell-art Aug 17, 2024
9023e3f
[design] 미디엄 폰트 다시 추가
lybell-art Aug 17, 2024
24e9e47
[design] 어드민 페이지 폰트 굵기 수정
lybell-art Aug 17, 2024
1e04392
[design] 메인 페이지 폰트 굵기 수정
lybell-art Aug 17, 2024
8b226a7
[design] 메인 페이지 폰트 굵기 수정 2
lybell-art Aug 17, 2024
ffb1a95
[feat] 보조금 인터랙션 동전 애니메이션 중첩되어서 나오게 수정
lybell-art Aug 17, 2024
70b9b82
[chore] 선착순 이벤트 id 임시로 숫자로 수정
lybell-art Aug 17, 2024
a1af4af
[feat] 이벤트 등록 추첨 인원수 설정 추가
lybell-art Aug 17, 2024
74b65fb
[design] 이벤트 등록 헤더 상단에 고정
lybell-art Aug 17, 2024
d5a5d4d
[feat] 이벤트 등록-정책 작성 폼 추가
lybell-art Aug 17, 2024
b3605b4
[feat] 이벤트등록추첨정책삭제기능구현
lybell-art Aug 17, 2024
4f9ed55
[feat] 이벤트 등록 제출 기능 추가
lybell-art Aug 17, 2024
9ad97e4
[feat] 이벤트 생성 임시저장 기능 추가
lybell-art Aug 17, 2024
5780994
[fix] 이벤트 수정 mock api 오류 수정, 잘못된 임시저장 불러오기 막기 모달 안 뜨는 오류 수정
lybell-art Aug 17, 2024
6c6af1d
[fix] 이벤트 프레임 입력이 영숫자/하이픈/언더바만 받게 수정
lybell-art Aug 17, 2024
b4f8e21
[chore] 린트 수정 및 프리티어 적용
lybell-art Aug 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
7 changes: 3 additions & 4 deletions src/adminPage/features/eventEdit/DateTimeRangeInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ function dateToSplittedState(date) {
return formatDate(date, "YYYY-MM-DD hh:mm").split(" ");
}

function applyDateInputToDateObj(inputValue, timeValue) {
function applyDateInputToDateObj(inputValue, timeValue, defaultTime = "00:00") {
if (inputValue === "") return null;
const [y, m, d] = inputValue.split("-").map(Number);

let date =
timeValue === null ? new Date("1970.1.1 00:00") : new Date(timeValue);
let date = timeValue === null ? new Date(`1970.1.1 ${defaultTime}`) : new Date(timeValue);

date.setFullYear(y);
date.setMonth(m - 1);
Expand Down Expand Up @@ -56,7 +55,7 @@ function DateTimeRangeInput({

function setEndDate(value) {
if (value === "") return setRange([range[0], null]);
let date = applyDateInputToDateObj(value, range[1]);
let date = applyDateInputToDateObj(value, range[1], "23:55");
if (range[0] === null || date >= range[0]) setRange([range[0], date]);
else setRange([range[0], range[0]]);
}
Expand Down
5 changes: 0 additions & 5 deletions src/adminPage/features/eventEdit/DrawInput.jsx

This file was deleted.

45 changes: 45 additions & 0 deletions src/adminPage/features/eventEdit/DrawInput/DrawMetadataInput.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { useContext } from "react";
import { EventEditContext, EventEditDispatchContext } from "../businessLogic/context.js";
import DrawMetadataItemInput from "./DrawMetadataItemInput.jsx";

function DrawMetadataInput() {
const {
draw: { metadata },
} = useContext(EventEditContext);
const dispatch = useContext(EventEditDispatchContext);

return (
<div className="flex flex-col gap-4">
<div className="flex justify-left items-center gap-2 h-10 text-body-l">
<span className="font-bold">
등수<sup className="text-red-500">*</sup> :{" "}
</span>
<select
className="w-24 h-full text-body-l font-medium"
value={metadata.size}
onChange={(e) => dispatch({ type: "modify_draw_total_grade", value: +e.target.value })}
>
{Array.from({ length: 10 }, (_, i) => (
<option value={i + 1} key={`select-grades-${i}`}>
{i + 1}
</option>
))}
</select>
</div>
<div className="flex flex-col gap-2">
<div className="grid grid-cols-[3rem_6rem_1fr] gap-4 font-bold items-center">
<div className="text-center">등수</div>
<div className="text-center">인원 수</div>
<div className="text-center">경품</div>
</div>
<div className="grid grid-cols-[3rem_6rem_1fr] gap-4 gap-y-2 font-regular items-center">
{[...metadata].map((data) => (
<DrawMetadataItemInput key={data.grade} {...data} />
))}
</div>
</div>
</div>
);
}

export default DrawMetadataInput;
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useContext } from "react";
import { EventEditDispatchContext } from "../businessLogic/context.js";
import { Input } from "@admin/components/SmallInput.jsx";

function DrawMetadataItemInput({ grade, count, prizeInfo }) {
const dispatch = useContext(EventEditDispatchContext);
const modify = (value) =>
dispatch({ type: "modify_draw_grade_item", value: { grade, ...value } });

return (
<>
<div className="text-center font-medium">{grade}등</div>
<div className="text-center">
<Input
text={count}
required
setText={(value) => modify({ count: Number.isNaN(+value) ? 0 : +value })}
inputMode="numeric"
pattern="[0-9]+"
size="3"
placeholder="인원"
/>
</div>
<Input
text={prizeInfo}
setText={(value) => modify({ prizeInfo: value })}
placeholder="경품 이름 입력"
/>
</>
);
}

export default DrawMetadataItemInput;
29 changes: 29 additions & 0 deletions src/adminPage/features/eventEdit/DrawInput/DrawPolicyInput.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useContext } from "react";
import { EventEditContext, EventEditDispatchContext } from "../businessLogic/context.js";
import DrawPolicyItemInput from "./DrawPolicyItemInput.jsx";
import Button from "@common/components/Button.jsx";

function DrawPolicyInput() {
const {
draw: { policies },
} = useContext(EventEditContext);
const dispatch = useContext(EventEditDispatchContext);

return (
<div className="flex flex-col gap-4">
<div className="grid grid-cols-[3fr_1fr_3rem] gap-4 items-center font-bold">
<div className="text-center">액션</div>
<div className="text-center">배율</div>
<div className="text-center">삭제</div>
</div>
<div className="grid grid-cols-[3fr_1fr_3rem] gap-4 gap-y-2 items-center font-medium">
{[...policies].map(({ key, ...data }) => (
<DrawPolicyItemInput key={key} uniqueKey={key} {...data} />
))}
</div>
<Button onClick={() => dispatch({ type: "add_draw_policy" })}>+ 추가하기</Button>
</div>
);
}

export default DrawPolicyInput;
44 changes: 44 additions & 0 deletions src/adminPage/features/eventEdit/DrawInput/DrawPolicyItemInput.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useContext } from "react";
import { EventEditDispatchContext } from "../businessLogic/context.js";
import { Input } from "@admin/components/SmallInput.jsx";
import DeleteButton from "@admin/components/DeleteButton";

const POLICY_ENUM = [
["WriteComment", "기대평 작성"],
["ParticipateEvent", "이벤트 참여"],
];

function DrawPolicyItemInput({ action, score, uniqueKey }) {
const dispatch = useContext(EventEditDispatchContext);
const modify = (value) => dispatch({ type: "modify_draw_policy", key: uniqueKey, value });

return (
<>
<select
className="invalid:text-neutral-400"
value={action}
required
onChange={(e) => modify({ action: e.target.value })}
>
<option value="">-정책을 설정하세요-</option>
{POLICY_ENUM.map(([key, text]) => (
<option value={key} key={key}>
{text}
</option>
))}
</select>
<Input
text={score}
required
setText={(value) => modify({ score: Number.isNaN(+value) ? 0 : +value })}
inputMode="numeric"
pattern="[0-9]+"
size="6"
placeholder="점수 배율"
/>
<DeleteButton onClick={() => dispatch({ type: "delete_draw_policy", key: uniqueKey })} />
</>
);
}

export default DrawPolicyItemInput;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function DrawSectionTitle({ children }) {
return (
<p className="font-bold text-body-l relative after:w-80 after:h-px after:absolute after:-bottom-1 after:left-0 after:border-b after:border-neutral-200">
{children}
</p>
);
}

export default DrawSectionTitle;
20 changes: 20 additions & 0 deletions src/adminPage/features/eventEdit/DrawInput/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import DrawSectionTitle from "./DrawSectionTitle.jsx";
import DrawMetadataInput from "./DrawMetadataInput.jsx";
import DrawPolicyInput from "./DrawPolicyInput.jsx";

function DrawInput() {
return (
<div className="w-full flex flex-col items-center gap-10">
<div className="flex flex-col gap-3 w-full max-w-[800px]">
<DrawSectionTitle>인원수 및 경품 설정</DrawSectionTitle>
<DrawMetadataInput />
</div>
<div className="flex flex-col gap-6 w-full max-w-[800px]">
<DrawSectionTitle>정책 설정</DrawSectionTitle>
<DrawPolicyInput />
</div>
</div>
);
}

export default DrawInput;
Loading