From daf0c9fc292a784c2eb1c33103f40a80d72b05ff Mon Sep 17 00:00:00 2001 From: foxholic9 Date: Tue, 11 Jun 2024 16:15:04 +0900 Subject: [PATCH 1/6] =?UTF-8?q?Feat:=20=EC=BB=AC=EB=9F=BC=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8A=94=20api=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 목록은 오류없이 잘 렌더링 됩니다. 현재 card목록은 수정중입니다. --- src/api/columns/apiColumns.tsx | 48 +++----- .../components/Column/Column.tsx | 103 ++++++++++++++---- .../components/ColumnHeader/ColumnHeader.tsx | 27 ++++- src/pages/dashboard.{dashboardid}/index.tsx | 35 +++--- 4 files changed, 142 insertions(+), 71 deletions(-) diff --git a/src/api/columns/apiColumns.tsx b/src/api/columns/apiColumns.tsx index b2efb14..4c9a692 100644 --- a/src/api/columns/apiColumns.tsx +++ b/src/api/columns/apiColumns.tsx @@ -1,13 +1,6 @@ import instance from '../axiosInstance'; import { handleResponse } from '../errorHandler'; -export interface ColumnOverAll { - id: number; - title: string; - createdAt: string; - updatedAt: string; -} - export interface CreateColumnBody { title: string; dashboardId: number; @@ -21,23 +14,19 @@ export interface UploadCardImageBody { image: string; } -interface ColumnOverAllResponse { - status: number; - data: ColumnOverAll; +export interface ColumnOverAll { + id: number; + title: string; + createdAt: string; + updatedAt: string; } -interface GetColumnResponse { - status: number; - result?: 'SUCCESS'; - data: { - cursorId: number; - totalCount: number; - dashboards: ColumnOverAll[]; - }; +export interface GetColumnListResponse { + result: string; + data: ColumnOverAll[]; } -interface UploadCardImageResponse { - status: number; +export interface UploadCardImageResponse { imageUrl: string; } @@ -46,8 +35,8 @@ interface UploadCardImageResponse { // 컬럼 생성 api export async function apiCreateColumn( body: CreateColumnBody, -): Promise { - const res = await instance.post('/cards', body); +): Promise { + const res = await instance.post('/columns', body); return handleResponse(res); } @@ -55,8 +44,8 @@ export async function apiCreateColumn( // dashboardId를 파라미터로 받습니다. export async function apiGetColumnList( dashboardId: number, -): Promise { - const res = await instance.get('/cards', { +): Promise { + const res = await instance.get('/columns', { params: { dashboardId, }, @@ -69,18 +58,15 @@ export async function apiGetColumnList( export async function apiUpdateColumn( body: UpdateColumnBody, columnId: number, -): Promise { - const res = await instance.put( - `/cards/${columnId}`, - body, - ); +): Promise { + const res = await instance.put(`/columns/${columnId}`, body); return handleResponse(res); } // 컬럼 삭제 // columnId를 파라미터로 받습니다. export async function apiDeleteColumn(columnId: number) { - const res = await instance.delete(`/cards/${columnId}`); + const res = await instance.delete(`/columns/${columnId}`); return handleResponse(res); } @@ -91,7 +77,7 @@ export async function apiUploadCardImage( columnId: number, ): Promise { const res = await instance.post( - `/cards/${columnId}/card-image`, + `/columns/${columnId}/card-image`, body, ); return handleResponse(res); diff --git a/src/pages/dashboard.{dashboardid}/components/Column/Column.tsx b/src/pages/dashboard.{dashboardid}/components/Column/Column.tsx index 874e572..35657da 100644 --- a/src/pages/dashboard.{dashboardid}/components/Column/Column.tsx +++ b/src/pages/dashboard.{dashboardid}/components/Column/Column.tsx @@ -1,46 +1,103 @@ +import { useEffect, useRef, useState } from 'react'; +import { AxiosError } from 'axios'; import styles from './Column.module.scss'; import ColumnCard from '../ColumnCard/ColumnCard'; import ColumnHeader from '../ColumnHeader/ColumnHeader'; import { AddNewTaskBtn } from '../../../../components/Btn/Btn'; +import { apiGetCardList, CardOverAll } from '../../../../api/apiModule'; +import useInfiniteScroll from '../../../../hooks/pagination/useInfiniteScroll'; interface ColumnProps { title: string; + columnId: number; } - -function Column({ title }: ColumnProps) { +function Column({ title, columnId }: ColumnProps) { const handleAddTaskBtn = () => {}; + const [cardList, setCardList] = useState([]); + const [cursor, setCursor] = useState(0); + const [totalCount, setTotalCount] = useState(0); + const [hasNext, setHasNext] = useState(true); + const [errorState, setErrorState] = useState(null); + + // 스크롤 관련 ref + const columnRef = useRef(null); + + // 다음에 불러오는 카드 수 + const PAGE_SIZE = 5; + + console.log(columnId); + const getFirstCardList = async () => { + try { + const res = await apiGetCardList({ columnId }); + const firstList = res.cards; + setCursor(res.cursorId); + setTotalCount(res.totalCount); + setCardList(firstList); + if (firstList.length < 10) setHasNext(false); + } catch (error) { + const axiosError = error as AxiosError; + setErrorState(axiosError.message || '목록을 가져오는데 실패했습니다'); + } + }; - const CardProps = { - assignee: 'unknown', - title: 'title', - dueDate: new Date('1915-08-15 19:20:30'), - tags: ['프론트', '프로젝트', '월요일', '좋아'], + const getMoreCardList = async () => { + try { + const res = await apiGetCardList({ + size: PAGE_SIZE, + cursorId: cursor, + columnId, + }); + const moreList = res.cards; + setCursor(res.cursorId); + setCardList((prevList) => [...prevList, ...moreList]); + if (moreList.length < PAGE_SIZE) setHasNext(false); + } catch (error) { + const axiosError = error as AxiosError; + setErrorState(axiosError.message || '목록을 가져오는데 실패했습니다'); + } }; - const CardProps2 = { - assignee: 'unknown', - title: 'title', - dueDate: new Date('1915-08-15 19:20:30'), - tags: ['프론트', '백엔드', '프로젝트', '월요일', '좋아'], - imageUrl: '/img/test_img.png', + + const setElement = useInfiniteScroll(getMoreCardList, { + root: null, + rootMargin: '20px', + threshold: 0.5, + }); + + useEffect(() => { + getFirstCardList(); + }); + + // 스크롤을 맨 위로 초기화 + const handleHeaderClick = () => { + if (columnRef.current) { + columnRef.current.scrollTop = 0; + } }; return (
+
{errorState}
- +
- - - - - - - - - + {cardList.map((cardData) => ( + + ))} + {hasNext &&
}
); } diff --git a/src/pages/dashboard.{dashboardid}/components/ColumnHeader/ColumnHeader.tsx b/src/pages/dashboard.{dashboardid}/components/ColumnHeader/ColumnHeader.tsx index e4a99a5..7fa3ce8 100644 --- a/src/pages/dashboard.{dashboardid}/components/ColumnHeader/ColumnHeader.tsx +++ b/src/pages/dashboard.{dashboardid}/components/ColumnHeader/ColumnHeader.tsx @@ -1,16 +1,35 @@ import ColorDot from '../../../../components/chip/ColorCircle/ColorDot'; import styles from './ColumnHeader.module.scss'; import NumChip from '../../../../components/chip/NumChip/NumChip'; +import useWindowSize from '../../../../utils/useWindowSize'; interface ColumnHeaderProps { name: string; + totalNum: number; + onClick: () => void; } -function ColumnHeader({ name }: ColumnHeaderProps) { +function ColumnHeader({ name, totalNum, onClick }: ColumnHeaderProps) { + const { width } = useWindowSize(); + + const handleClick = (event: React.MouseEvent) => { + if (width < 1024) return; + + const target = event.target as HTMLElement; + // ColorDot이나 settingButton을 클릭했을 경우 onClick을 무시합니다. + if ( + target.closest(`.${styles.settingButton}`) || + target.closest(`.${styles.colorDot}`) + ) { + return; + } + onClick(); + }; + return ( -
- +
+
{name}
- +
From c2170d6bea3b608bba51289c8a2f86a3a67e9904 Mon Sep 17 00:00:00 2001 From: foxholic9 Date: Wed, 12 Jun 2024 15:09:12 +0900 Subject: [PATCH 5/6] =?UTF-8?q?Fix:=20lint=EC=97=90=EB=9F=AC=EC=88=98?= =?UTF-8?q?=EC=A0=95,=20=EC=9E=84=EC=8B=9C=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 아직 모달 연결이 안되었습니다. to top 버튼 동작 테스트 중이던 lint에러가 발생해 임시로 수정합니다. --- .../components/ColumnHeader/ColumnHeader.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/pages/dashboard.{dashboardid}/components/ColumnHeader/ColumnHeader.tsx b/src/pages/dashboard.{dashboardid}/components/ColumnHeader/ColumnHeader.tsx index 7fa3ce8..2f05193 100644 --- a/src/pages/dashboard.{dashboardid}/components/ColumnHeader/ColumnHeader.tsx +++ b/src/pages/dashboard.{dashboardid}/components/ColumnHeader/ColumnHeader.tsx @@ -16,21 +16,22 @@ function ColumnHeader({ name, totalNum, onClick }: ColumnHeaderProps) { const target = event.target as HTMLElement; // ColorDot이나 settingButton을 클릭했을 경우 onClick을 무시합니다. - if ( - target.closest(`.${styles.settingButton}`) || - target.closest(`.${styles.colorDot}`) - ) { + if (target.closest(`.${styles.colorDot}`)) { return; } onClick(); }; return ( -
+
{name}
-