1- import { useEffect , useRef , useState , useCallback } from "react" ;
1+ import { useEffect , useState } from "react" ;
22import {
33 DndContext ,
44 closestCenter ,
@@ -13,99 +13,51 @@ import {
1313 arrayMove ,
1414} from "@dnd-kit/sortable" ;
1515import { CardType } from "@/types/task" ;
16- import SortableCard from "@/components/columnCard/SortableCard" ;
1716import { getCardsByColumn } from "@/api/card" ;
17+ import SortableCard from "@/components/columnCard/SortableCard" ;
18+ import { toast } from "react-toastify" ;
1819
19- type CardListProps = {
20+ interface CardListProps {
2021 columnId : number ;
2122 teamId : string ;
2223 initialTasks : CardType [ ] ;
2324 onCardClick : ( card : CardType ) => void ;
24- } ;
25-
26- const ITEMS_PER_PAGE = 6 ;
25+ }
2726
28- export default function CardList ( {
29- columnId,
27+ export const CardList = ( {
3028 initialTasks,
29+ columnId,
3130 onCardClick,
32- } : CardListProps ) {
33- const [ cards , setCards ] = useState < CardType [ ] > ( initialTasks ) ;
34- const [ cursorId , setCursorId ] = useState < number | null > (
35- initialTasks . length > 0 ? initialTasks [ initialTasks . length - 1 ] . id : null
36- ) ;
37- const [ hasMore , setHasMore ] = useState ( true ) ;
38- const observerRef = useRef < HTMLDivElement | null > ( null ) ;
39- const isFetchingRef = useRef ( false ) ;
31+ } : CardListProps ) => {
32+ const [ cards , setCards ] = useState < CardType [ ] > ( [ ] ) ;
4033
4134 const sensors = useSensors (
4235 useSensor ( PointerSensor , {
43- activationConstraint : {
44- distance : 5 ,
45- } ,
36+ activationConstraint : { distance : 5 } ,
4637 } )
4738 ) ;
4839
49- const fetchMoreCards = useCallback ( async ( ) => {
50- if ( isFetchingRef . current || ! hasMore ) return ;
51-
52- isFetchingRef . current = true ;
53-
54- try {
55- const res = await getCardsByColumn ( {
56- columnId,
57- size : ITEMS_PER_PAGE ,
58- cursorId : cursorId ?? undefined ,
59- } ) ;
60-
61- const newCards = res . cards as CardType [ ] ;
62-
63- if ( newCards . length > 0 ) {
64- setCards ( ( prev ) => {
65- const existingIds = new Set ( prev . map ( ( card ) => card . id ) ) ;
66- const uniqueCards = newCards . filter (
67- ( card ) => ! existingIds . has ( card . id )
68- ) ;
69- return [ ...prev , ...uniqueCards ] ;
70- } ) ;
71-
72- setCursorId ( ( prevCursorId ) => {
73- const newCursor = newCards [ newCards . length - 1 ] ?. id ?? prevCursorId ;
74- return newCursor ;
40+ // 카드 목록 api 호출 (마감일 빠른 순 정렬)
41+ useEffect ( ( ) => {
42+ const fetchCards = async ( ) => {
43+ try {
44+ const res = await getCardsByColumn ( { columnId } ) ;
45+ const sorted = [ ...res . cards ] . sort ( ( a , b ) => {
46+ const dateA = a . dueDate ? new Date ( a . dueDate ) . getTime ( ) : Infinity ;
47+ const dateB = b . dueDate ? new Date ( b . dueDate ) . getTime ( ) : Infinity ;
48+ return dateA - dateB ;
7549 } ) ;
50+ setCards ( sorted ) ;
51+ } catch ( error ) {
52+ console . error ( "카드 불러오기 실패:" , error ) ;
53+ toast . error ( "카드를 불러오는 데 실패했습니다." ) ;
7654 }
55+ } ;
7756
78- if ( newCards . length < ITEMS_PER_PAGE ) {
79- setHasMore ( false ) ;
80- }
81- } catch ( error ) {
82- console . error ( "카드 로딩 실패:" , error ) ;
83- } finally {
84- isFetchingRef . current = false ;
85- }
86- } , [ columnId , cursorId , hasMore ] ) ;
87-
88- useEffect ( ( ) => {
89- if ( ! observerRef . current ) return ;
90-
91- const observer = new IntersectionObserver (
92- ( entries ) => {
93- if ( entries [ 0 ] . isIntersecting && hasMore ) {
94- fetchMoreCards ( ) ;
95- }
96- } ,
97- { threshold : 0.5 }
98- ) ;
99-
100- observer . observe ( observerRef . current ) ;
101-
102- return ( ) => observer . disconnect ( ) ;
103- } , [ fetchMoreCards , hasMore ] ) ;
104-
105- useEffect ( ( ) => {
106- setCards ( initialTasks ) ;
107- } , [ initialTasks ] ) ;
57+ fetchCards ( ) ;
58+ } , [ columnId , initialTasks ] ) ;
10859
60+ // 드래그 & 드롭
10961 const handleDragEnd = ( event : DragEndEvent ) => {
11062 const { active, over } = event ;
11163
@@ -118,30 +70,22 @@ export default function CardList({
11870 setCards ( newOrder ) ;
11971 } ;
12072
121- // 마감일 빠른 순 정렬
122- const sortedCards = [ ...cards ] . sort ( ( a , b ) => {
123- const dateA = a . dueDate ? new Date ( a . dueDate ) . getTime ( ) : Infinity ;
124- const dateB = b . dueDate ? new Date ( b . dueDate ) . getTime ( ) : Infinity ;
125- return dateA - dateB ;
126- } ) ;
127-
12873 return (
12974 < DndContext
13075 sensors = { sensors }
13176 collisionDetection = { closestCenter }
13277 onDragEnd = { handleDragEnd }
13378 >
13479 < SortableContext
135- items = { sortedCards . map ( ( card ) => card . id ) }
80+ items = { cards . map ( ( card ) => card . id ) }
13681 strategy = { verticalListSortingStrategy }
13782 >
13883 < div className = "grid gap-3 w-full grid-cols-1" >
139- { sortedCards . map ( ( card ) => (
84+ { cards . map ( ( card ) => (
14085 < SortableCard key = { card . id } card = { card } onClick = { onCardClick } />
14186 ) ) }
142- { hasMore && < div ref = { observerRef } className = "h-20" /> }
14387 </ div >
14488 </ SortableContext >
14589 </ DndContext >
14690 ) ;
147- }
91+ } ;
0 commit comments