diff --git a/src/api/homeListMockData.ts b/src/api/homeListMockData.ts new file mode 100644 index 0000000..3a66cff --- /dev/null +++ b/src/api/homeListMockData.ts @@ -0,0 +1,31 @@ +import { TabType } from '@/components/molecules/homeList/HomeListTab'; + +export type ListItem = { title: string; date: string }; + +export type TabListData = { + todo?: ListItem[]; + done?: ListItem[]; +}; + +export const mockData: Record = { + together: { + todo: [ + { title: '함께 준비할 리스트 1', date: '2025.07.21' }, + { title: '함께 준비할 리스트 2', date: '2025.07.24' }, + { title: '함께 준비할 리스트 3', date: '2025.07.23' }, + { title: '함께 준비할 리스트 4', date: '2025.07.10' }, + ], + done: [{ title: '함께 완료한 리스트', date: '2025.07.22' }], + }, + bride: { + todo: [ + { title: '예신 준비할 리스트 1', date: '2025.07.21' }, + { title: '예신 준비할 리스트 2', date: '2025.07.24' }, + { title: '예신 준비할 리스트 3', date: '2025.07.23' }, + ], + done: [{ title: '예신 완료한 리스트', date: '2025.07.21' }], + }, + groom: { + done: [{ title: '예랑 완료한 리스트', date: '2025.07.23' }], + }, +}; diff --git a/src/app/home-list/page.tsx b/src/app/home-list/page.tsx new file mode 100644 index 0000000..da1a7cc --- /dev/null +++ b/src/app/home-list/page.tsx @@ -0,0 +1,72 @@ +'use client'; + +import { ListItem, mockData } from '@/api/homeListMockData'; +import { HomeListItem } from '@/components/molecules/homeList'; +import { HomeListType } from '@/components/molecules/homeList/HomeListCard'; +import { + HomeListDropdown, + HomeListDropdownType, +} from '@/components/molecules/homeList/HomeListDropdown'; +import { TabType } from '@/components/molecules/homeList/HomeListTab'; +import { TopBar } from '@/components/molecules/topBar'; +import { useSearchParams } from 'next/navigation'; +import { useMemo, useState } from 'react'; + +const labelMap: Record = { + together: '함께', + bride: '예신', + groom: '예랑', +}; + +const HomeListPage = () => { + const searchParams = useSearchParams(); + const type = (searchParams.get('type') ?? 'todo') as HomeListType; + const role = (searchParams.get('role') ?? 'together') as TabType; + + const title = + type === 'done' + ? `${labelMap[role]} 완료한 리스트` + : `${labelMap[role]} 할 리스트`; + + const [sortedOption, setSortedOption] = + useState('날짜순'); + const items: ListItem[] = mockData[role]?.[type] ?? []; + + const sortedItems = useMemo(() => { + if (sortedOption === '날짜순') { + return [...items].sort( + (a, b) => new Date(b.date).getTime() - new Date(a.date).getTime(), + ); + } + // TODO: 카테고리순 정렬 + return items; + }, [items, sortedOption]); + + return ( + <> + +
+

{title}

+
+ {`총 ${items.length}개`} + +
+
+ {sortedItems.map(({ title, date }) => ( + + ))} +
+
+ + ); +}; + +export default HomeListPage; diff --git a/src/components/atoms/dropdown/Dropdown.tsx b/src/components/atoms/dropdown/Dropdown.tsx index 1e8c827..e888005 100644 --- a/src/components/atoms/dropdown/Dropdown.tsx +++ b/src/components/atoms/dropdown/Dropdown.tsx @@ -8,7 +8,7 @@ interface DropdownProps { export const Dropdown = ({ options }: DropdownProps) => { return ( -
+
{options.map((option, index) => (
{index > 0 &&
} diff --git a/src/components/molecules/homeList/HomeListDropdown.tsx b/src/components/molecules/homeList/HomeListDropdown.tsx index 6ada760..d8d99a7 100644 --- a/src/components/molecules/homeList/HomeListDropdown.tsx +++ b/src/components/molecules/homeList/HomeListDropdown.tsx @@ -3,10 +3,17 @@ import DownArrow from '@/assets/wed_icon/icon_16/downarrow_default_gray 800.svg'; import { Dropdown } from '@/components/atoms/dropdown'; import { useDropdown } from '@/hooks/useDropdown'; -import { useState } from 'react'; -export const HomeListDropdown = () => { - const [selectedOption, setSelectedOption] = useState('날짜순'); +export type HomeListDropdownType = '날짜순' | '카테고리순'; +interface HomeListDropdownProps { + selectedOption: HomeListDropdownType; + onSelectAction: (value: HomeListDropdownType) => void; +} + +export const HomeListDropdown = ({ + selectedOption, + onSelectAction, +}: HomeListDropdownProps) => { const { isDropdownOpen, handleToggleDropdown, dropdownRef, triggerRef } = useDropdown(); @@ -19,7 +26,7 @@ export const HomeListDropdown = () => { { label: '날짜순', onClick: () => { - setSelectedOption('날짜순'); + onSelectAction('날짜순'); console.log('날짜순 정렬'); handleToggleDropdown(); }, @@ -27,7 +34,7 @@ export const HomeListDropdown = () => { { label: '카테고리순', onClick: () => { - setSelectedOption('카테고리순'); + onSelectAction('카테고리순'); console.log('카테고리순 정렬'); handleToggleDropdown(); }, @@ -39,7 +46,7 @@ export const HomeListDropdown = () => {
{selectedOption} diff --git a/src/components/molecules/homeList/HomeListTab.tsx b/src/components/molecules/homeList/HomeListTab.tsx new file mode 100644 index 0000000..a68490a --- /dev/null +++ b/src/components/molecules/homeList/HomeListTab.tsx @@ -0,0 +1,34 @@ +'use client'; + +export type TabType = 'together' | 'bride' | 'groom'; + +interface TabSelectorProps { + selectedTab: TabType; + onSelectTab: (tab: TabType) => void; +} + +const tabLabels: Record = { + together: '함께', + bride: '예신', + groom: '예랑', +}; + +const tabs: TabType[] = ['together', 'bride', 'groom']; + +export const TabSelector = ({ selectedTab, onSelectTab }: TabSelectorProps) => { + return ( +
+ {tabs.map((tab) => ( + + ))} +
+ ); +}; diff --git a/src/components/molecules/homeList/homeListCard.tsx b/src/components/molecules/homeList/homeListCard.tsx index 7495bdb..81e96d7 100644 --- a/src/components/molecules/homeList/homeListCard.tsx +++ b/src/components/molecules/homeList/homeListCard.tsx @@ -3,7 +3,7 @@ import RightArrow from '@/assets/wed_icon/icon_16/rightarrow_default_gray 800.svg'; import { HomeListItem } from './HomeListItem'; -type HomeListType = 'done' | 'todo'; +export type HomeListType = 'done' | 'todo'; const titleMap: Record = { done: '완료한 리스트', diff --git a/src/components/molecules/progress/TabProgressCard.tsx b/src/components/molecules/progress/TabProgressCard.tsx index b89fa14..7ce09d3 100644 --- a/src/components/molecules/progress/TabProgressCard.tsx +++ b/src/components/molecules/progress/TabProgressCard.tsx @@ -1,84 +1,43 @@ 'use client'; -import { useEffect, useState } from 'react'; +import { mockData } from '@/api/homeListMockData'; +import { TabType } from '../homeList/HomeListTab'; import { DonutProgress } from './DonutProgress'; - -const tabs = ['함께', '예신', '예랑'] as const; -type TabType = (typeof tabs)[number]; -type ProgressDataMap = Record; - -type ProgressInfo = { - label: string; - total: number; - remaining: number; -}; - -// mock data -const fetchProgressData = async (): Promise => { - await new Promise((r) => setTimeout(r, 300)); - - return { - 함께: { label: '함께', total: 20, remaining: 12 }, - 예신: { label: '예신', total: 5, remaining: 1 }, - 예랑: { label: '예랑', total: 4, remaining: 4 }, - }; -}; - -export const TabProgressCard = () => { - const [selectedTab, setSelectedTab] = useState('함께'); - const [progressData, setProgressData] = useState(); - - useEffect(() => { - // TODO : 서버에서 받아와야함 - fetchProgressData().then(setProgressData); - }, []); - - if (!progressData) { - return
loading...
; - } - - const { label, total, remaining } = progressData[selectedTab]; +interface TabProgressCardProps { + selectedTab: TabType; +} + +export const TabProgressCard = ({ selectedTab }: TabProgressCardProps) => { + const tabData = mockData[selectedTab]; + const total = (tabData.todo?.length ?? 0) + (tabData.done?.length ?? 0); + const remaining = tabData.todo?.length ?? 0; const percentage = total > 0 ? Math.round(((total - remaining) / total) * 100) : 0; - return ( -
- {/* 탭 메뉴 */} -
- {tabs.map((tab) => ( - - ))} -
+ const labelMap: Record = { + together: '함께', + bride: '예신', + groom: '예랑', + }; - {/* 콘텐츠 카드 */} -
-
- {/* 텍스트 */} -
-
- {label} -
-
- 결혼 준비 진행률 -
-
- {total}개 중 {remaining}개 남았어요! -
+ return ( +
+
+ {/* 텍스트 */} +
+
+ {labelMap[selectedTab]}
- - {/* 도넛 차트 */} -
- +
결혼 준비 진행률
+
+ {total}개 중 {remaining}개 남았어요!
+ + {/* 도넛 차트 */} +
+ +
); diff --git a/src/features/home/Home.tsx b/src/features/home/Home.tsx index 66aaa23..4d45089 100644 --- a/src/features/home/Home.tsx +++ b/src/features/home/Home.tsx @@ -1,21 +1,30 @@ 'use client'; +import { ListItem, mockData } from '@/api/homeListMockData'; import { BottomNavigation } from '@/components/molecules/bottomNavigation'; import { HomeListCard } from '@/components/molecules/homeList'; +import { + TabSelector, + TabType, +} from '@/components/molecules/homeList/HomeListTab'; import MemoLink from '@/components/molecules/memo/MemoLink'; import { Navigation } from '@/components/molecules/navigation'; import { ProgressCard, TabProgressCard } from '@/components/molecules/progress'; - -// mock data -const homeListItems = [ - { title: '촬영업체 선택1', date: '2025.07.08' }, - { title: '촬영업체 선택2', date: '2025.07.08' }, - { title: '촬영업체 선택3', date: '2025.07.08' }, - { title: '촬영업체 선택4', date: '2025.07.08' }, - { title: '촬영업체 선택5', date: '2025.07.08' }, -]; +import { useRouter } from 'next/navigation'; +import { useEffect, useState } from 'react'; export const Home = () => { + const router = useRouter(); + const [selectedTab, setSelectedTab] = useState('together'); + const [todoItems, setTodoItems] = useState([]); + const [doneItems, setDoneItems] = useState([]); + + useEffect(() => { + const data = mockData[selectedTab]; + setTodoItems(data.todo ?? []); + setDoneItems(data.done ?? []); + }, [selectedTab]); + return (
@@ -23,16 +32,21 @@ export const Home = () => { {/* TODO : percentage 받아오기 */} - + + console.log('남은 리스트 click')} + items={todoItems} + onClick={() => + router.push(`/home-list?type=todo&role=${selectedTab}`) + } /> console.log('완료한 리스트 click')} + items={doneItems} + onClick={() => + router.push(`/home-list?type=done&role=${selectedTab}`) + } />