-
Notifications
You must be signed in to change notification settings - Fork 6
요청주제관리 페이지 UI 수정 및 API 연동 #285
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
Changes from all commits
667ce40
c7c7369
53ca41d
7f27b29
a28d20c
923047f
f23dc3f
d9d1257
7c69284
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| 'use client'; | ||
| import { useMutation, useQueryClient } from '@tanstack/react-query'; | ||
|
|
||
| import BottomSheet from './BottomSheet'; | ||
|
|
||
| import { RequestedTopicType } from '@/lib/types/requestedTopicType'; | ||
| import editAdminTopic from '@/app/_api/adminTopics/editAdminTopic'; | ||
| import formatDate from '@/lib/utils/dateFormat'; | ||
| import { QUERY_KEYS } from '@/lib/constants/queryKeys'; | ||
| import useBooleanOutput from '@/hooks/useBooleanOutput'; | ||
|
|
||
| import * as styles from './AdminTopicBox.css'; | ||
|
|
||
| interface TopicBoxProps { | ||
| topic: RequestedTopicType; | ||
| } | ||
|
|
||
| function TopicBox({ topic }: TopicBoxProps) { | ||
| const queryClient = useQueryClient(); | ||
| const { isOn: isBottomSheetOpen, handleSetOn, handleSetOff } = useBooleanOutput(); | ||
|
|
||
| const editTopicMutation = useMutation({ | ||
| mutationFn: () => | ||
| editAdminTopic({ | ||
| topicId: topic?.id, | ||
| isExposed: !topic.isExposed, | ||
| title: topic?.title, | ||
| categoryCode: topic?.categoryCode, | ||
| }), | ||
| onSuccess: () => { | ||
| queryClient.invalidateQueries({ | ||
| queryKey: [QUERY_KEYS.getAdminTopics], | ||
| }); | ||
| }, | ||
| }); | ||
|
|
||
| const handleClickEditButton = () => { | ||
| handleSetOn(); | ||
| }; | ||
|
|
||
| const handleToggleExposeButton = () => { | ||
| editTopicMutation.mutate(); | ||
| }; | ||
|
|
||
| return ( | ||
| <> | ||
| <tr className={styles.bodyRow}> | ||
| <td>{formatDate(topic?.createdDate)}</td> | ||
| <td>{topic?.categoryKorName}</td> | ||
| <td className={styles.rowItem}> | ||
| <span className={styles.rowText}>{topic?.title}</span> | ||
| <span className={styles.rowText}>{topic?.description}</span> | ||
| </td> | ||
| <td className={styles.buttons}> | ||
| <span className={styles.rowText}> | ||
| {topic?.isAnonymous ? `${topic?.ownerNickname}(익명 요청)` : topic?.ownerNickname} | ||
| </span> | ||
| </td> | ||
| <td className={styles.buttons}> | ||
| <button className={styles.editButton} onClick={handleClickEditButton}> | ||
| 수정하기 | ||
| </button> | ||
| </td> | ||
| <td> | ||
| <select onChange={handleToggleExposeButton} value={topic?.isExposed ? '공개' : '비공개'}> | ||
| <option>공개</option> | ||
| <option>비공개</option> | ||
| </select> | ||
| </td> | ||
| </tr> | ||
|
|
||
| {isBottomSheetOpen && ( | ||
| <BottomSheet | ||
| onClose={() => { | ||
| handleSetOff(); | ||
| }} | ||
| topicTitle={topic?.title} | ||
| category={topic?.categoryKorName} | ||
| isExposed={topic?.isExposed} | ||
| topicId={topic?.id} | ||
| /> | ||
| )} | ||
| </> | ||
| ); | ||
| } | ||
|
|
||
| export default TopicBox; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,28 +2,26 @@ | |
|
|
||
| import * as styles from './BottomSheet.css'; | ||
| import { MouseEventHandler, useState } from 'react'; | ||
| import { useMutation, useQuery } from '@tanstack/react-query'; | ||
| import { useUser } from '@/store/useUser'; | ||
| import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; | ||
| import { QUERY_KEYS } from '@/lib/constants/queryKeys'; | ||
| import useOnClickOutside from '@/hooks/useOnClickOutside'; | ||
| import getCategories from '@/app/_api/category/getCategories'; | ||
| import editAdminTopic from '@/app/_api/adminTopics/editAdminTopic'; | ||
|
|
||
| import { CategoryType } from '@/lib/types/categoriesType'; | ||
| import ArrowDown from '/public/icons/down_chevron.svg'; | ||
| import useBooleanOutput from '@/hooks/useBooleanOutput'; | ||
| import Modal from '@/components/Modal/Modal'; | ||
|
|
||
| interface BottomSheetProps { | ||
| onClose: MouseEventHandler<HTMLDivElement>; | ||
| onClose: () => void; | ||
| topicTitle: string; | ||
| category: string; | ||
| isExposed: boolean; | ||
| topicId: number; | ||
| } | ||
| // TODO: 컴포넌트 공통화 작업 | ||
| function BottomSheet({ onClose, topicTitle, category, isExposed }: BottomSheetProps) { | ||
| function BottomSheet({ onClose, topicTitle, category, isExposed, topicId }: BottomSheetProps) { | ||
| const [isDropdownOpen, setIsDropdownOpen] = useState(false); | ||
| const { isOn: isModalOn, handleSetOn: openModal, handleSetOff: closeModal } = useBooleanOutput(false); | ||
| const queryClient = useQueryClient(); | ||
|
|
||
| const [title, setTitle] = useState(topicTitle); | ||
| const [selectedCategory, setSelectedCategory] = useState<string>(category); | ||
|
|
@@ -35,17 +33,26 @@ function BottomSheet({ onClose, topicTitle, category, isExposed }: BottomSheetPr | |
| queryFn: getCategories, | ||
| }); | ||
|
|
||
| const convertCategoryKorNameToCode = (korName: string) => { | ||
| const category = categories?.find((cat) => cat.korName === korName); | ||
| return category ? category.code : null; // 찾지 못하면 null 반환 | ||
| }; | ||
|
|
||
| const editTopicMutation = useMutation({ | ||
| // mutationFn: () => | ||
| // editAdminTopic({ | ||
| // isExposed, | ||
| // title, | ||
| // categoryCode, | ||
| // }), | ||
| mutationFn: () => | ||
| editAdminTopic({ | ||
| topicId, | ||
| isExposed, | ||
| title, | ||
| categoryCode: convertCategoryKorNameToCode(selectedCategory as string) || '', | ||
| }), | ||
|
Comment on lines
+36
to
+48
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 추후 리팩토링 하실 때 드롭다운을 ul, li태그가 아닌 select 태그를 사용하는 것으로 수정하면 카테고리 선택하고, 뮤테이션에 넣어주는 부분에 대해 코드 가독성면에서 좋을 것 같아요, 아래 코드 참고 부탁드립니당
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 리팩토링 시 꼭 코드 반영하겠습니다. 조언 감사합니다 소현님! |
||
| onSuccess: () => { | ||
| setTitle(''); | ||
| setSelectedCategory(selectedCategory); | ||
| openModal(); | ||
| queryClient.invalidateQueries({ | ||
| queryKey: [QUERY_KEYS.getAdminTopics], | ||
| }); | ||
| onClose(); | ||
| }, | ||
| onError: (error) => { | ||
| setErrorMessage('요청 중 오류가 발생했습니다. 다시 시도해 주세요. :('); | ||
|
|
@@ -131,24 +138,10 @@ function BottomSheet({ onClose, topicTitle, category, isExposed }: BottomSheetPr | |
| </div> | ||
|
|
||
| <button type="submit" className={styles.submitButton} disabled={!title || title.length > 30}> | ||
| 요청 보내기 | ||
| 수정하기 | ||
| </button> | ||
| </form> | ||
| </div> | ||
| {isModalOn && ( | ||
| <Modal handleModalClose={closeModal} size="large"> | ||
| <div className={styles.modalText}>{`요청 주제 수정이 완료되었어요.`} </div> | ||
| <button | ||
| className={styles.modalButton} | ||
| onClick={() => { | ||
| closeModal(); | ||
| setIsDropdownOpen(false); //실행안됨 | ||
| }} | ||
| > | ||
| 닫기 | ||
| </button> | ||
| </Modal> | ||
| )} | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| import { style } from '@vanilla-extract/css'; | ||
| import { vars } from '@/styles/theme.css'; | ||
| import * as fonts from '@/styles/font.css'; | ||
|
|
||
| export const body = style({ | ||
| width: '100%', | ||
| minHeight: '100vh', | ||
| padding: '1.5rem', | ||
|
|
||
| display: 'flex', | ||
| flexDirection: 'column', | ||
| rowGap: '12px', | ||
| }); | ||
|
|
||
| export const title = style([ | ||
| fonts.Subtitle, | ||
| { | ||
| color: vars.color.black, | ||
| }, | ||
| ]); | ||
|
|
||
| export const subtitle = style([ | ||
| fonts.Body, | ||
| { | ||
| paddingBottom: '15px', | ||
| color: vars.color.bluegray8, | ||
| }, | ||
| ]); | ||
|
|
||
| export const table = style({ | ||
| maxWidth: '850px', | ||
| padding: '1rem', | ||
|
|
||
| display: 'flex', | ||
| flexDirection: 'column', | ||
| gap: '1rem', | ||
|
|
||
| backgroundColor: vars.color.white, | ||
| borderRadius: '8px', | ||
| }); | ||
|
|
||
|
Comment on lines
+30
to
+41
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 스타일 파일에 사용하지 않는 클래스네임이 많은 것 같아서 제거하면 좋을 것 같습니당!
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Nahyun-Kang 나현님, 혹시 해당 리뷰는 반영되었을까요? 👀
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ParkSohyunee 네 소현님! 필요없는 css 코드는 삭제해두었습니다!👀 |
||
| export const headRow = style([ | ||
| fonts.BodyRegular, | ||
| { | ||
| padding: '1rem 0.5rem', | ||
|
|
||
| display: 'grid', | ||
| gridTemplateColumns: 'repeat(8, 1fr)', | ||
| alignItems: 'center', | ||
|
|
||
| textAlign: 'center', | ||
| }, | ||
| ]); | ||
|
|
||
| export const rowItem = style({ | ||
| gridColumn: 'span 2', | ||
|
|
||
| display: 'flex', | ||
| flexDirection: 'column', | ||
| gap: '0.5rem', | ||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(의견) 혹시 요청 주제 관리 페이지에서 토글로 노출상태를 바로 변경하는 기능을 두신 이유가 무엇인지 궁금합니당 👀
공지의 경우는 생성/수정 필드와 노출 관련 API가 분리되어 있는 상황이었는데, 요청 주제 관리는 수정 바텀시트에서 함께 수정할 수 있을 것 같다는 생각이 들어서요~! 중복 코드도 제거할 수 있고, 사용성 면에서도 불편함이 없을 것 같아서 제안드려봅니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
소현님 이 부분은 와이어프레임을 보고 그대로 만든 건데 바텀시트 안에 들어있어도 좋을 것 같습니다! 다만 이번 PR 말고 다른 PR로 따로 올려서 서영님과 상의를 거친 후 수정해보겠습니다!