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/party room admin 페이지 구현 #1247 #1330

Merged
merged 8 commits into from
Mar 27, 2024
2 changes: 2 additions & 0 deletions components/admin/party/PartyNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useState } from 'react';
import styles from 'styles/party/PartyNav.module.scss';
import PartyCategory from './PartyCategory';
import PartyReportNav from './PartyReportNav';
import PartyRoomTable from './PartyRoomTable';
import PartyTemplate from './PartyTemplate';

export default function PartyNav() {
Expand All @@ -28,6 +29,7 @@ export default function PartyNav() {
</ul>

{navValue === 'report' && <PartyReportNav />}
{navValue === 'room' && <PartyRoomTable />}
{navValue === 'template' && <PartyTemplate />}
{navValue === 'category' && <PartyCategory />}
</div>
Expand Down
104 changes: 104 additions & 0 deletions components/admin/party/PartyRoomTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { useState } from 'react';
import { useSetRecoilState } from 'recoil';
import {
Paper,
Table,
TableBody,
TableCell,
TableContainer,
TableRow,
} from '@mui/material';
import { PartyRoomColumn } from 'types/admin/adminPartyTypes';
import { dateToStringShort } from 'utils/handleTime';
import { modalState } from 'utils/recoil/modal';
import { tableFormat } from 'constants/admin/table';
import AdminSearchBar from 'components/admin/common/AdminSearchBar';
import { AdminTableHead } from 'components/admin/common/AdminTable';
import PageNation from 'components/Pagination';
import useAdminPartyRoomList from 'hooks/party/useAdminPartyRoomList';
import styles from 'styles/admin/party/AdminPartyCommon.module.scss';

const tableTitle: { [key: string]: string } = {
roomId: 'ID',
title: '제목',
categoryName: '카테고리',
createDate: '생성일',
dueDate: '마감일',
creatorIntraId: '작성자',
roomStatus: '상태', // 숨김 보이기 표시
etc: '기타',
};

export default function PartyRoomTable() {
const setModal = useSetRecoilState(modalState);
const [currentPage, setCurrentPage] = useState(1);
const { partyRooms, totalPages } = useAdminPartyRoomList({
page: currentPage,
});
// const [searchKeyword, setSearchKeyword] = useState('');

const rooms: PartyRoomColumn[] = partyRooms.map((room) => ({
roomId: room.roomId,
title: room.title,
categoryName: room.categoryName,
createDate: dateToStringShort(new Date(room.createDate)),
dueDate: dateToStringShort(new Date(room.dueDate)),
creatorIntraId: room.creatorIntraId ?? '',
roomStatus: room.status,
}));

return (
<div className={styles.AdminTableWrap}>
<div className={styles.header}>
<span className={styles.title}>파티방 관리</span>
{/* <AdminSearchBar
initSearch={(keyword) => {
setSearchKeyword(keyword ?? '');
// updateRoomsByTitle(searchKeyword);
}}
/> */}
</div>
<TableContainer component={Paper} className={styles.tableContainer}>
<Table aria-label='partyRoomTable' className={styles.table}>
<AdminTableHead tableName={'partyRoom'} table={tableTitle} />
<TableBody className={styles.tableBody}>
{rooms.map((room) => (
<TableRow key={room.roomId}>
{tableFormat['partyRoom'].columns.map((columnName) => (
<TableCell key={columnName} className={styles.tableBodyItem}>
{columnName !== 'etc' ? (
<div>
{room[columnName as keyof PartyRoomColumn] ?? '없음'}
</div>
) : (
<button
onClick={() => {
setModal({
modalName: 'ADMIN-PARTY_EDIT',
roomId: room.roomId,
});
}}
className={`${styles.button_1} ${styles.edit}`}
>
자세히
</button>
)}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<div className={styles.pageNationContainer}>
<PageNation
curPage={currentPage}
totalPages={totalPages}
pageChangeHandler={(pageNumber: number) => {
setCurrentPage(pageNumber);
}}
/>
</div>
</div>
);
}
135 changes: 135 additions & 0 deletions components/modal/Party/PartyRoomEditModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import Image from 'next/image';
import { ChangeEvent, useEffect, useState } from 'react';
import { useSetRecoilState } from 'recoil';
import { Switch } from '@mui/material';
import {
PartyComment,
PartyRoomDetail,
PartyRoomStatus,
roomStatusOpts,
} from 'types/partyTypes';
import { instanceInPartyManage } from 'utils/axios';
import { dateToStringShort } from 'utils/handleTime';
import { toastState } from 'utils/recoil/toast';
import styles from 'styles/admin/party/PartyRoomEdit.module.scss';

export default function PartyRoomEditModal({ roomId }: { roomId: number }) {
const setSnackBar = useSetRecoilState(toastState);
const [room, setRoom] = useState<PartyRoomDetail>();

function handleStatus(e: ChangeEvent<HTMLSelectElement>) {
setRoom({
...(room as PartyRoomDetail),
status: e.target.value as PartyRoomStatus,
});
}
function handleCommentHidden(comment: PartyComment) {
instanceInPartyManage
.patch(`/comments/${comment.commentId}`, {
isHidden: !comment.isHidden,
})
.then(() => {
setRoom({
...room!,
comments: room!.comments.map((c) =>
c.commentId === comment.commentId
? { ...c, isHidden: !comment.isHidden }
: c
),
});
})
.catch(() => {
setSnackBar({
toastName: 'PATCH request',
message: '코멘트를 수정할 수 없습니다',
severity: 'error',
clicked: true,
});
});
}

useEffect(() => {
instanceInPartyManage
.get(`/rooms/${roomId}`)
.then(({ data }: { data: PartyRoomDetail }) => {
setRoom(data);
});
}, []);

if (!room) return null;

return (
<div className={styles.container}>
<header className={styles.roomHeader}>
<h2>
<span className={styles.categoryName}>#{room.categoryName}</span>
{room.title}
</h2>
<select onChange={handleStatus}>
{roomStatusOpts.map((opt) => (
<option key={opt} value={opt}>
{opt}
</option>
))}
</select>
</header>
<section className={styles.roomDate}>
<div>작성일: {dateToStringShort(new Date(room.createDate))}</div>
<div>마감일: {dateToStringShort(new Date(room.dueDate))}</div>
</section>
<section className={styles.roomContent}>
<p>{room.content}</p>
</section>
<section className={styles.roomUsers}>
<h3>
현재 {room.roomUsers.length} | 모집인원{' '}
{`${room.minPeople} - ${room.maxPeople}`}
</h3>
<ul>
{room.roomUsers.map((user) => (
<li key={user.roomUserId}>
<div className={styles.userImage}>
<Image
src={user.userImage ?? ''}
objectFit='cover'
fill
alt='13'
/>
</div>
<div>{user.nickname}</div>
<div>({user.intraId})</div>
</li>
))}
</ul>
</section>
<section className={styles.roomComments}>
<h3>코멘트</h3>
<ul>
{room.comments.map((comment) => (
<li key={comment.commentId}>
<header>
<div>
<span className={styles.commentUserName}>
{comment.nickname}
</span>
<span className={styles.commentDate}>
{dateToStringShort(new Date(comment.createDate))}
</span>
</div>
<div>
{comment.isHidden ? '숨겨짐' : ''}
<Switch
checked={comment.isHidden}
onChange={() => handleCommentHidden(comment)}
inputProps={{ 'aria-label': 'hidden switch' }}
/>
</div>
</header>
<p>{comment.content}</p>
</li>
))}
</ul>
</section>
</div>
);
}
3 changes: 3 additions & 0 deletions components/modal/modalType/AdminModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import AdminSeasonEdit from 'components/modal/admin/SeasonEdit';
import TemplateModal from 'components/modal/Party/TemplateModal';
import AdminEditTournamentBraket from '../admin/AdminEditTournamentBraket';
import AdminTournamentParticipantEditModal from '../admin/AdminTournamentParticipantEditModal/AdminTournamentParticipantEditModal';
import PartyRoomEditModal from '../Party/PartyRoomEditModal';

export default function AdminModal() {
const {
Expand All @@ -36,6 +37,7 @@ export default function AdminModal() {
tournament,
tournamentId,
template,
roomId,
} = useRecoilValue(modalState);

if (!modalName) {
Expand Down Expand Up @@ -93,6 +95,7 @@ export default function AdminModal() {
<AdminTournamentParticipantEditModal tournamentId={tournamentId} />
) : null,
'ADMIN-PARTY_TEMPLATE': <TemplateModal template={template} />,
'ADMIN-PARTY_EDIT': roomId ? <PartyRoomEditModal roomId={roomId} /> : null,
};

return content[modalName];
Expand Down
38 changes: 38 additions & 0 deletions hooks/party/useAdminPartyRoomList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useEffect, useState } from 'react';
import { PartyRoom } from 'types/partyTypes';
import { instanceInPartyManage } from 'utils/axios';

type PartyRoomListProps = {
searchTitle?: string;
page: number;
};
type RoomListResponse = {
adminRoomList: PartyRoom[];
totalPages: number;
};

export default function useAdminPartyRoomList(
{ searchTitle, page }: PartyRoomListProps = { page: 1 }
) {
const [partyRooms, setPartyRooms] = useState<PartyRoom[]>([]);
const [totalPages, setTotalPages] = useState(1);

const getRoomsAxios = (title?: string) => {
const titleQuery = title ? `&title=${title}` : '';
return instanceInPartyManage.get<RoomListResponse>(
`/rooms?page=${page}&size=10${titleQuery}`
);
};

useEffect(() => {
getRoomsAxios().then(({ data }) => {
setPartyRooms(data.adminRoomList);
setTotalPages(data.totalPages);
});
}, [searchTitle, page]);

return {
partyRooms,
totalPages,
};
}
10 changes: 2 additions & 8 deletions hooks/party/usePartyRoomList.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { useEffect, useState } from 'react';
import { PartyRoom } from 'types/partyTypes';
import { instance, instanceInPartyManage } from 'utils/axios';
import { instance } from 'utils/axios';

type PartyRoomListProps = {
isAdmin?: boolean;
withJoined?: boolean;
searchTitle?: string;
};
Expand All @@ -12,7 +11,6 @@ type RoomListResponse = {
};

export default function usePartyRoomList({
isAdmin = false,
withJoined = false,
searchTitle,
}: PartyRoomListProps = {}) {
Expand All @@ -21,11 +19,7 @@ export default function usePartyRoomList({

const getRoomsAxios = (title?: string) => {
const query = title ? `?title=${title}` : '';
return isAdmin
? instanceInPartyManage.get<RoomListResponse>(
'/party/admin/rooms' + query
)
: instance.get<RoomListResponse>('/party/rooms' + query);
return instance.get<RoomListResponse>('/party/rooms' + query);
};

useEffect(() => {
Expand Down
45 changes: 0 additions & 45 deletions hooks/party/usePartyRoomList.tsx

This file was deleted.

Loading