Skip to content
22 changes: 19 additions & 3 deletions src/apis/rolling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,18 @@ export const getCurrentRollingPaper = async (): Promise<RollingPaperInformation>

export const getRollingPaperDetail = async (
rollingPaperId: string | number,
page: number,
size: number,
): Promise<RollingPaper> => {
const {
data: { data },
} = await client.get(`/api/event-posts/${rollingPaperId}`);
} = await client.get(`/api/event-posts/${rollingPaperId}`, {
params: {
page,
size,
},
});
console.log(data);
return data;
};

Expand Down Expand Up @@ -49,11 +57,19 @@ export const postNewRollingPaper = async (title: string) => {
}
};

export const getRollingPaperList = async (): Promise<RollingPaperList> => {
export const getRollingPaperList = async (
page: string | number,
size: number,
): Promise<RollingPaperList> => {
try {
const {
data: { data },
} = await client.get('/api/admin/event-posts');
} = await client.get('/api/admin/event-posts', {
params: {
page,
size,
},
});
return data;
} catch (error) {
console.error(error);
Expand Down
2 changes: 1 addition & 1 deletion src/components/BackgroundBottom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const BackgroundBottom = () => {
return (
<BackgroundImageWrapper
as="div"
className="fixed bottom-[-40px] left-1/2 z-[-10] h-42 w-full -translate-x-1/2 opacity-70"
className="fixed bottom-[-40px] left-1/2 h-42 w-full -translate-x-1/2 opacity-70"
imageUrl={BgItem}
/>
);
Expand Down
1 change: 0 additions & 1 deletion src/components/ConfirmModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ const ConfirmModal = ({
onCancel,
onConfirm,
}: ConfirmModalProps) => {
// TODO: 전역 상태로 관리해야하는지 고민
return (
<ModalOverlay>
<div className="w-73">
Expand Down
31 changes: 25 additions & 6 deletions src/pages/Admin/RollingPaper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,28 @@ import PageTitle from './components/AdminPageTitle';
import RollingPaperItem from './components/RollingPaperItem';
import WrapperFrame from './components/WrapperFrame';
import WrapperTitle from './components/WrapperTitle';
import PagenationNavigation from './components/PagenationNavigation';

const SIZE = 10;

export default function AdminRollingPaper() {
const [activeModal, setActiveModal] = useState(false);
const { data, isLoading, isSuccess } = useQuery({
queryKey: ['admin-rolling-paper'],
queryFn: getRollingPaperList,
const [currentPage, setCurrentPage] = useState<string>('1');
const { data, isLoading, isSuccess, refetch } = useQuery({
queryKey: ['admin-rolling-paper', currentPage],
queryFn: () => getRollingPaperList(currentPage ?? 1, SIZE),
});

const handleNowPage = (page: string) => {
setCurrentPage(page);
refetch();
};

return (
<>
{activeModal && <AddRollingPaperModal onClose={() => setActiveModal(false)} />}
{activeModal && (
<AddRollingPaperModal currentPage={currentPage} onClose={() => setActiveModal(false)} />
)}
<PageTitle>게시판 관리 / 롤링 페이퍼 설정</PageTitle>
<WrapperFrame>
<section className="flex items-center">
Expand Down Expand Up @@ -47,7 +58,11 @@ export default function AdminRollingPaper() {
</thead>
<tbody>
{data.content.map((rollingPaper) => (
<RollingPaperItem key={rollingPaper.eventPostId} information={rollingPaper} />
<RollingPaperItem
key={rollingPaper.eventPostId}
information={rollingPaper}
currentPage={currentPage}
/>
))}
</tbody>
</table>
Expand All @@ -58,7 +73,11 @@ export default function AdminRollingPaper() {
)}
</>
)}
{/* TODO: 페이지네이션 적용 */}
<PagenationNavigation
totalPage={Number(data?.totalPages)}
buttonLength={5}
handlePageNumberButtonClick={handleNowPage}
/>
Comment on lines +76 to +80
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

페이지네이션 사용은 괜찮으신가요?? 문제점이나 개선사항 있다면 수정하겠습니다!!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 사용할 땐 괜찮았어요!! 굳굳입니당~~~

</WrapperFrame>
</>
);
Expand Down
6 changes: 3 additions & 3 deletions src/pages/Admin/components/AddRollingPaperModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import { postNewRollingPaper } from '@/apis/rolling';
import ModalOverlay from '@/components/ModalOverlay';

interface AddRollingPaperModalProps {
currentPage: number | string;
onClose: () => void;
}

export default function AddRollingPaperModal({ onClose }: AddRollingPaperModalProps) {
export default function AddRollingPaperModal({ currentPage, onClose }: AddRollingPaperModalProps) {
const [title, setTitle] = useState('');
const [error, setError] = useState('');
const queryClient = useQueryClient();
Expand All @@ -19,8 +20,7 @@ export default function AddRollingPaperModal({ onClose }: AddRollingPaperModalPr
setTitle('');
setError('');
onClose();
// TODO: 페이지네이션 적용 후, 현재 page에 대한 캐싱 날리는 방식으로 변경
queryClient.invalidateQueries({ queryKey: ['admin-rolling-paper'] });
queryClient.invalidateQueries({ queryKey: ['admin-rolling-paper', currentPage] });
},
onError: () => {
setError('편지 작성에 실패했어요. 다시 시도해주세요.');
Expand Down
10 changes: 5 additions & 5 deletions src/pages/Admin/components/PagenationNavigation.tsx
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

css 수정해주셔서 더 보기 좋군요 헣👍👍🥕

Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ export default function PagenationNavigation({
}
};

const buttonStyle = 'border bg-white px-2 py-1 disabled:bg-gray-20';
const buttonStyle = 'rounded-full bg-white w-8 h-8 disabled:bg-gray-20';

return (
<div className="mt-5 flex h-10 w-full items-center justify-center">
<div className="flex items-center">
<div className="flex items-center gap-2">
<button
className={twMerge(buttonStyle)}
className={twMerge(buttonStyle, 'w-14')}
disabled={nowSection <= 0}
onClick={() => {
handlePrevButtonClick();
Expand All @@ -69,7 +69,7 @@ export default function PagenationNavigation({
return (
<button
key={num}
className={twMerge(buttonStyle, nowPageNumberAt === num && 'bg-accent-3')}
className={twMerge(buttonStyle, nowPageNumberAt === num && 'bg-primary-2/50')}
onClick={() => {
handlePageButtonClick(num);
}}
Expand All @@ -79,7 +79,7 @@ export default function PagenationNavigation({
);
})}
<button
className={twMerge(buttonStyle)}
className={twMerge(buttonStyle, 'w-14')}
disabled={nowSection >= totalSection}
onClick={() => {
handleNextButtonClick();
Expand Down
86 changes: 50 additions & 36 deletions src/pages/Admin/components/RollingPaperItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@ import { AxiosError } from 'axios';

import { deleteRollingPaper, patchRollingPaper } from '@/apis/rolling';
import { DeleteIcon } from '@/assets/icons';
import { useState } from 'react';
import ConfirmModal from '@/components/ConfirmModal';

interface RollingPaperItemProps {
information: AdminRollingPaperInformation;
currentPage: string | number;
}
Comment on lines 9 to 12
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

props 인터페이스는 컴포넌트 파일에 있는게 직관성이 좋아보이는데 그래도 나중에 d.ts폴더로 옮기는게 좋을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

d.ts는 아무래도 인터페이스를 전역적으로 사용할 수 있는 특징이 있다보니 컴포넌트 내에서만 사용되는 props의 경우에는 굳이 d.ts로 옮기지는 않아도 된다고 생각했어요! 오히려 수정이나 구성을 확인할 때 파일 이동이 있어서 번거로울 것 같기도 하구요!


export default function RollingPaperItem({ information }: RollingPaperItemProps) {
export default function RollingPaperItem({ information, currentPage }: RollingPaperItemProps) {
const [activeDeleteModal, setActiveDeleteModal] = useState(false);
const queryClient = useQueryClient();

const { mutate: deleteMutate } = useMutation({
mutationFn: () => deleteRollingPaper(information.eventPostId),
onSuccess: () => {
// TODO: 페이지네이션 적용 후, 현재 page에 대한 캐싱 날리는 방식으로 변경
queryClient.invalidateQueries({ queryKey: ['admin-rolling-paper'] });
queryClient.invalidateQueries({ queryKey: ['admin-rolling-paper', currentPage] });
},
onError: (err) => {
console.error(err);
Expand All @@ -25,9 +28,7 @@ export default function RollingPaperItem({ information }: RollingPaperItemProps)
const { mutate: toggleStatus } = useMutation({
mutationFn: () => patchRollingPaper(information.eventPostId),
onSuccess: () => {
// TODO: 기존 데이터 수정하는 방식으로 ㄱㄱㄱㄱㄱㄱㄱ
// 일단 임시로 캐싱 날리기
queryClient.invalidateQueries({ queryKey: ['admin-rolling-paper'] });
queryClient.invalidateQueries({ queryKey: ['admin-rolling-paper', currentPage] });
},
onError: (err: AxiosError<{ code: string; message: string }>) => {
if (err.response?.data.code === 'EVENT-004') {
Expand All @@ -37,40 +38,53 @@ export default function RollingPaperItem({ information }: RollingPaperItemProps)
},
});

// TODO: 진짜 삭제하겠냐고 물어보기
return (
<tr className="border-gray-40 h-14 border-b">
<td className="w-14 text-center">{information.eventPostId}</td>
<td className="text-left">
<div>
{information.used && (
<span className="mr-2 rounded-full border border-amber-500 bg-amber-100/70 px-3 py-0.5 whitespace-nowrap text-amber-500">
진행 중
</span>
)}
{information.title}
</div>
</td>
<td className="text-center">
<button
type="button"
className="hover:bg-gray-10 text-gray-60 rounded-md px-3 py-1 hover:text-black"
onClick={() => toggleStatus()}
>
{information.used ? '중단하기' : '진행하기'}
</button>
</td>
<td className="w-6">
{!information.used && (
<>
{activeDeleteModal && (
<ConfirmModal
title="정말 롤링페이퍼를 삭제하시겠어요?"
description="롤링페이퍼를 삭제하는 경우 복구가 불가능합니다!"
cancelText="되돌아가기"
confirmText="삭제하기"
onCancel={() => {
setActiveDeleteModal(false);
}}
onConfirm={deleteMutate}
/>
)}
<tr className="border-gray-40 h-14 border-b">
<td className="w-14 text-center">{information.eventPostId}</td>
<td className="text-left">
<div>
{information.used && (
<span className="mr-2 rounded-full border border-amber-500 bg-amber-100/70 px-3 py-0.5 whitespace-nowrap text-amber-500">
진행 중
</span>
)}
{information.title}
</div>
</td>
<td className="text-center">
<button
type="button"
className="text-gray-60 flex items-center justify-center p-1 hover:text-black"
onClick={() => deleteMutate()}
className="hover:bg-gray-10 text-gray-60 rounded-md px-3 py-1 hover:text-black"
onClick={() => toggleStatus()}
>
<DeleteIcon className="h-5 w-5" />
{information.used ? '중단하기' : '진행하기'}
</button>
Comment on lines 68 to 74
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 지금 빼먹은게 산더미라서 할 말 없지만 aria-label 속성이었나? 그걸 넣어야 접근성이 좋아진다고 gpt랑 승연님이 알려주셨어용(저도 나중에 수정해야 할 거 같아요🥲)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 aria-label에 대해서 잘 몰라서 질문하고 싶어요..! button 내부의 텍스트가 충분히 의도를 설명한다고 생각했는데, aria-label이 추가적으로 더 필요한 이유가 있을까요?!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aria-label을 설정하면 시각 장애인등의 이용자가 스크린 리더 기능을 사용해서 해당 버튼에 대한 설명을 음성으로 들을수 있다고 하네요! 실제로 써 본적이 없어서 크게 도움이 될까 싶긴 한데 그래도 웹접근성을 높이는 방법 중에 하나라고 하니.. 일단 넣어두면 나쁘지 않을거 같습니다!!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오홍.. 제가 알기로는 aria-label이 스크린 리더로 읽을 때 충분히 의미가 전달되지 않는 요소에 대해서 적절하게 라벨을 붙여주는 것이라고 이해하고 있었어요. 그래서 이미 태그에 내용이 충분하게 있음에도 aria-label이 필요할까 했었구요! 아래 글을 참고해봤어요!!

https://velog.io/@kinsk2839/Buttons-do-not-have-an-accessible-name-%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0-with-aria-label

)}
</td>
</tr>
</td>
<td className="w-6">
{!information.used && (
<button
type="button"
className="text-gray-60 flex items-center justify-center p-1 hover:text-black"
onClick={() => setActiveDeleteModal(true)}
>
Comment on lines +78 to +82
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aria-label

<DeleteIcon className="h-5 w-5" />
</button>
)}
</td>
</tr>
</>
);
}
2 changes: 1 addition & 1 deletion src/pages/LetterBoard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const LetterBoardPage = () => {

return (
<>
<main className="mt-[-25px] flex grow flex-col px-5 pt-20 pb-10">
<main className="z-1 mt-[-25px] flex grow flex-col px-5 pt-20 pb-10">
<>
<NoticeRollingPaper />
<PageTitle className="mx-auto mt-4">게시판</PageTitle>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/MyPage/components/MyBoardPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const MyBoardPage = () => {
}
return (
<>
<main className={twMerge('flex grow flex-col px-5 pt-20 pb-10')}>
<main className={twMerge('z-1 flex grow flex-col px-5 pt-20 pb-10')}>
<PageTitle className="mx-auto mb-11">내가 올린 게시물</PageTitle>
{isLoading ? (
<p>loading</p>
Expand Down
12 changes: 5 additions & 7 deletions src/pages/RollingPaper/components/WriteCommentButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import { useState } from 'react';
import { postRollingPaperComment } from '@/apis/rolling';
import EnvelopeImg from '@/assets/images/closed-letter.png';
import MessageModal from '@/components/MessageModal';

const DUMMY_USER_ZIP_CODE = '1DR41';
import useAuthStore from '@/stores/authStore';

interface WriteCommentButtonProps {
rollingPaperId: string;
Expand All @@ -15,12 +14,12 @@ const WriteCommentButton = ({ rollingPaperId }: WriteCommentButtonProps) => {
const [activeMessageModal, setActiveMessageModal] = useState(false);
const [newMessage, setNewMessage] = useState('');
const [error, setError] = useState<string | null>(null);
const zipCode = useAuthStore((props) => props.zipCode);
const queryClient = useQueryClient();

const { mutate } = useMutation({
mutationFn: (content: string) => postRollingPaperComment(rollingPaperId, content),
onSuccess: (data) => {
console.log(data);
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['rolling-paper', rollingPaperId] });
setNewMessage('');
setError(null);
Expand All @@ -37,7 +36,6 @@ const WriteCommentButton = ({ rollingPaperId }: WriteCommentButtonProps) => {

const handleAddComment = () => {
console.log(rollingPaperId);
// 추가 가능한지 조건 확인
if (newMessage.trim() === '') {
setError('편지를 작성해주세요.');
return;
Expand All @@ -59,12 +57,12 @@ const WriteCommentButton = ({ rollingPaperId }: WriteCommentButtonProps) => {
onComplete={handleAddComment}
>
<p className="body-r text-accent-1 mt-1">{error}</p>
<p className="body-r mt-5 text-end text-black">From. {DUMMY_USER_ZIP_CODE}</p>
<p className="body-r mt-5 text-end text-black">From. {zipCode}</p>
</MessageModal>
)}
<button
type="button"
className="fixed bottom-7.5 left-5 overflow-hidden rounded-sm"
className="sticky bottom-8 z-10 mt-4 -mb-4 self-start overflow-hidden rounded-sm"
onClick={() => setActiveMessageModal(true)}
>
<img src={EnvelopeImg} alt="편지지 이미지" className="h-12 w-auto opacity-70" />
Expand Down
Loading