|
| 1 | +'use client'; |
| 2 | + |
| 3 | +import { useEffect, useState } from 'react'; |
| 4 | + |
| 5 | +import PageHeader from '@/components/common/PageHeader'; |
| 6 | +import ToolBar from '@/components/tils/ToolBar'; |
| 7 | +import TilList from '@/components/tils/TilList'; |
| 8 | + |
| 9 | +import { useAuthUser } from '@/lib/auth/useAuthUser'; |
| 10 | +import { fetchTilList } from '@/lib/tils/tilListService'; |
| 11 | +import { deleteTil } from '@/services/write/til.service'; |
| 12 | + |
| 13 | +import type { TilItem } from '@/types/til'; |
| 14 | + |
| 15 | +const Page = () => { |
| 16 | + const { user, authLoading } = useAuthUser(); |
| 17 | + |
| 18 | + const [items, setItems] = useState<TilItem[]>([]); |
| 19 | + const [loading, setLoading] = useState(true); |
| 20 | + const [error, setError] = useState<string | null>(null); |
| 21 | + const [sort, setSort] = useState<'latest' | 'oldest'>('latest'); |
| 22 | + const [sortedItems, setSortedItems] = useState<TilItem[]>([]); |
| 23 | + |
| 24 | + const [searchTerm, setSearchTerm] = useState(''); |
| 25 | + |
| 26 | + // 데이터 가져오기 |
| 27 | + useEffect(() => { |
| 28 | + if (!user) { |
| 29 | + setItems([]); |
| 30 | + setLoading(false); |
| 31 | + return; |
| 32 | + } |
| 33 | + |
| 34 | + const loadData = async () => { |
| 35 | + try { |
| 36 | + setError(null); |
| 37 | + setLoading(true); |
| 38 | + const list = await fetchTilList(user.uid); |
| 39 | + setItems(list); |
| 40 | + } catch (e) { |
| 41 | + console.error(e); |
| 42 | + setError('일지 목록을 불러오지 못했습니다.'); |
| 43 | + } finally { |
| 44 | + setLoading(false); |
| 45 | + } |
| 46 | + }; |
| 47 | + |
| 48 | + loadData(); |
| 49 | + }, [user]); |
| 50 | + |
| 51 | + // 정렬 처리 |
| 52 | + useEffect(() => { |
| 53 | + const filtered = items.filter((item) => |
| 54 | + // 제목에서 검색어 포함 여부 확인 |
| 55 | + item.title.toLowerCase().includes(searchTerm.toLowerCase()) |
| 56 | + ); |
| 57 | + |
| 58 | + // 필터링된 결과를 정렬 |
| 59 | + const sorted = filtered.sort((a, b) => { |
| 60 | + return sort === 'latest' |
| 61 | + ? b.createdAt - a.createdAt |
| 62 | + : a.createdAt - b.createdAt; |
| 63 | + }); |
| 64 | + setSortedItems(sorted); |
| 65 | + }, [items, sort, searchTerm]); |
| 66 | + |
| 67 | + const handleDelete = async (id: string) => { |
| 68 | + if (!user) return; |
| 69 | + |
| 70 | + await deleteTil(user.uid, id); |
| 71 | + |
| 72 | + setItems((prev) => prev.filter((item) => item.id !== id)); |
| 73 | + }; |
| 74 | + |
| 75 | + const handleSortChange = (e: React.ChangeEvent<HTMLSelectElement>) => { |
| 76 | + setSort(e.target.value as 'latest' | 'oldest'); |
| 77 | + }; |
| 78 | + |
| 79 | + const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => { |
| 80 | + setSearchTerm(e.target.value); |
| 81 | + }; |
| 82 | + |
| 83 | + if (authLoading) { |
| 84 | + return ( |
| 85 | + <div className="flex min-h-screen items-center justify-center"> |
| 86 | + <p>로그인 확인 중...</p> |
| 87 | + </div> |
| 88 | + ); |
| 89 | + } |
| 90 | + |
| 91 | + if (!user) { |
| 92 | + return ( |
| 93 | + <div className="flex min-h-screen items-center justify-center"> |
| 94 | + <p>로그인이 필요합니다.</p> |
| 95 | + </div> |
| 96 | + ); |
| 97 | + } |
| 98 | + return ( |
| 99 | + <div className="bg-background flex min-h-screen flex-col gap-5 px-30 py-11"> |
| 100 | + <PageHeader |
| 101 | + title="일지" |
| 102 | + highlight="관리하기" |
| 103 | + description="작성한 일지를 관리해보세요" |
| 104 | + /> |
| 105 | + |
| 106 | + <ToolBar |
| 107 | + items={sortedItems} |
| 108 | + onChangeSort={handleSortChange} |
| 109 | + searchTerm={searchTerm} |
| 110 | + onSearch={handleSearch} |
| 111 | + /> |
| 112 | + |
| 113 | + {error && <p className="text-sm text-red-500">{error}</p>} |
| 114 | + |
| 115 | + {loading ? ( |
| 116 | + <p className="text-sm text-slate-400">불러오는 중...</p> |
| 117 | + ) : ( |
| 118 | + <TilList items={sortedItems} onDelete={handleDelete} /> |
| 119 | + )} |
| 120 | + </div> |
| 121 | + ); |
| 122 | +}; |
| 123 | + |
| 124 | +export default Page; |
0 commit comments