|
1 | | -import { BUY_ITEMS, FAVORITE_PRODUCT_ITEMS, FAVORITE_REPAIR_ITEMS, SELL_ITEMS } from '@shared/mocks/data/mypage'; |
2 | | -import { useState } from 'react'; |
| 1 | +import { |
| 2 | + useMyPageBuyHistoryQuery, |
| 3 | + useMyPageProfileQuery, |
| 4 | + useMyPageSellHistoryQuery, |
| 5 | + type TradeHistoryItem, |
| 6 | + type TradeHistoryQueryStatus, |
| 7 | + type TradeHistoryStatus, |
| 8 | +} from '@shared/apis/mypage'; |
| 9 | +import { |
| 10 | + useWishlistPostListQuery, |
| 11 | + useWishlistShopListQuery, |
| 12 | + type WishlistPostItem, |
| 13 | + type WishlistShopItem, |
| 14 | +} from '@shared/apis/wishlist'; |
| 15 | +import { useCallback, useMemo, useState } from 'react'; |
3 | 16 | import { createStatusTabs } from './createStatusTabs'; |
4 | 17 | import { filterTradeItems } from './filterTradeItems'; |
5 | 18 | import type { FavoriteCategory, FavoriteTabs, MainTabId, StatusFilter } from './types'; |
| 19 | +import type { TradeListItem } from '@pages/mypage/ui/TradeItemList'; |
| 20 | +import type { RepairListItem } from '@shared/ui/RepairList'; |
| 21 | + |
| 22 | +const formatPrice = (value: number) => `${new Intl.NumberFormat('ko-KR').format(value)}원`; |
| 23 | +const formatDate = (value: string) => { |
| 24 | + const date = new Date(value); |
| 25 | + if (Number.isNaN(date.getTime())) { |
| 26 | + return value; |
| 27 | + } |
| 28 | + const year = date.getFullYear(); |
| 29 | + const month = String(date.getMonth() + 1).padStart(2, '0'); |
| 30 | + const day = String(date.getDate()).padStart(2, '0'); |
| 31 | + return `${year}.${month}.${day}`; |
| 32 | +}; |
| 33 | + |
| 34 | +const mapHistoryItem = (item: TradeHistoryItem, options?: { statusLabel?: string }): TradeListItem => ({ |
| 35 | + id: String(item.postId), |
| 36 | + modelName: item.title, |
| 37 | + price: formatPrice(item.price), |
| 38 | + date: formatDate(item.createdAt), |
| 39 | + status: item.status === 'COMPLETED' ? 'completed' : 'buying', |
| 40 | + statusLabel: options?.statusLabel, |
| 41 | + imageUrl: item.thumbnailUrl ?? undefined, |
| 42 | +}); |
| 43 | + |
| 44 | +const mapWishlistPostItem = (item: WishlistPostItem, index: number): TradeListItem => { |
| 45 | + const resolvedId = item.postId ?? item.id ?? `wishlist-post-${index}`; |
| 46 | + return { |
| 47 | + id: String(resolvedId), |
| 48 | + modelName: item.title ?? '상품', |
| 49 | + price: item.price !== undefined ? formatPrice(item.price) : '가격 정보 없음', |
| 50 | + date: item.createdAt ? formatDate(item.createdAt) : '', |
| 51 | + status: 'favorite', |
| 52 | + favoriteActive: true, |
| 53 | + imageUrl: item.thumbnailUrl ?? item.thumbnail ?? undefined, |
| 54 | + }; |
| 55 | +}; |
| 56 | + |
| 57 | +const mapWishlistShopItem = (item: WishlistShopItem, index: number): RepairListItem => ({ |
| 58 | + id: `${item.shopName ?? 'shop'}-${index}`, |
| 59 | + name: item.shopName ?? '수리점', |
| 60 | + address: item.location ?? '', |
| 61 | + favoriteActive: true, |
| 62 | +}); |
6 | 63 |
|
7 | 64 | export const useMyPageState = () => { |
| 65 | + const { data: profileData } = useMyPageProfileQuery(); |
| 66 | + const { data: wishlistPosts = [] } = useWishlistPostListQuery(); |
| 67 | + const { data: wishlistShops = [] } = useWishlistShopListQuery(); |
8 | 68 | const [activeTab, setActiveTab] = useState<MainTabId>('buy'); |
9 | 69 | const [buyStatus, setBuyStatus] = useState<StatusFilter>('all'); |
10 | 70 | const [sellStatus, setSellStatus] = useState<StatusFilter>('all'); |
11 | 71 | const [favoriteCategory, setFavoriteCategory] = useState<FavoriteCategory>('product'); |
| 72 | + const [sellStatusOverrides, setSellStatusOverrides] = useState<Record<number, TradeHistoryStatus>>({}); |
| 73 | + |
| 74 | + const mapStatusToQuery = (status: StatusFilter): TradeHistoryQueryStatus => { |
| 75 | + if (status === 'completed') { |
| 76 | + return 'COMPLETED'; |
| 77 | + } |
| 78 | + if (status === 'buying') { |
| 79 | + return 'RESERVED'; |
| 80 | + } |
| 81 | + return 'ALL'; |
| 82 | + }; |
| 83 | + |
| 84 | + const buyStatusQuery = mapStatusToQuery(buyStatus); |
| 85 | + const sellStatusQuery = mapStatusToQuery(sellStatus); |
| 86 | + |
| 87 | + const { data: buyAllHistory } = useMyPageBuyHistoryQuery('ALL'); |
| 88 | + const { data: sellAllHistory } = useMyPageSellHistoryQuery('ALL'); |
| 89 | + const { data: buyHistory } = useMyPageBuyHistoryQuery(buyStatusQuery); |
| 90 | + const { data: sellHistory } = useMyPageSellHistoryQuery(sellStatusQuery); |
| 91 | + |
| 92 | + const buyItemsForCount = useMemo( |
| 93 | + () => (buyAllHistory ?? profileData?.buyList ?? []).map((item) => mapHistoryItem(item)), |
| 94 | + [buyAllHistory, profileData?.buyList] |
| 95 | + ); |
| 96 | + |
| 97 | + const resolveSellStatus = useCallback( |
| 98 | + (item: TradeHistoryItem): TradeHistoryStatus => { |
| 99 | + return sellStatusOverrides[item.postId] ?? item.status; |
| 100 | + }, |
| 101 | + [sellStatusOverrides] |
| 102 | + ); |
| 103 | + |
| 104 | + const mapSellHistoryItem = useCallback( |
| 105 | + (item: TradeHistoryItem): TradeListItem => { |
| 106 | + const resolvedStatus = resolveSellStatus(item); |
| 107 | + const mapped = mapHistoryItem( |
| 108 | + { |
| 109 | + ...item, |
| 110 | + status: resolvedStatus, |
| 111 | + }, |
| 112 | + { statusLabel: resolvedStatus === 'COMPLETED' ? '판매완료' : '판매중' } |
| 113 | + ); |
| 114 | + const uiStatus = resolvedStatus === 'COMPLETED' ? 'completed' : 'buying'; |
| 115 | + return { |
| 116 | + ...mapped, |
| 117 | + status: uiStatus, |
| 118 | + statusEditable: true, |
| 119 | + statusOptions: [ |
| 120 | + { value: 'buying', label: '판매중' }, |
| 121 | + { value: 'completed', label: '판매완료' }, |
| 122 | + ], |
| 123 | + onStatusChange: (nextStatus) => { |
| 124 | + const nextHistoryStatus: TradeHistoryStatus = nextStatus === 'completed' ? 'COMPLETED' : 'RESERVED'; |
| 125 | + setSellStatusOverrides((prev) => ({ |
| 126 | + ...prev, |
| 127 | + [item.postId]: nextHistoryStatus, |
| 128 | + })); |
| 129 | + }, |
| 130 | + }; |
| 131 | + }, |
| 132 | + [resolveSellStatus] |
| 133 | + ); |
| 134 | + |
| 135 | + const sellItemsForCount = useMemo( |
| 136 | + () => (sellAllHistory ?? []).map((item) => mapSellHistoryItem(item)), |
| 137 | + [sellAllHistory, mapSellHistoryItem] |
| 138 | + ); |
| 139 | + |
| 140 | + const buyItems = useMemo(() => { |
| 141 | + const serverItems = buyHistory ?? (buyStatusQuery === 'ALL' ? buyAllHistory : undefined); |
| 142 | + if (buyStatusQuery !== 'ALL' && serverItems && serverItems.length === 0 && buyItemsForCount.length) { |
| 143 | + return filterTradeItems(buyItemsForCount, buyStatus); |
| 144 | + } |
| 145 | + const baseItems = serverItems ?? buyAllHistory ?? profileData?.buyList ?? []; |
| 146 | + return baseItems.map((item) => |
| 147 | + mapHistoryItem(item, { statusLabel: item.status === 'COMPLETED' ? '구매완료' : '구매중' }) |
| 148 | + ); |
| 149 | + }, [buyHistory, buyStatusQuery, buyAllHistory, buyItemsForCount, buyStatus, profileData?.buyList]); |
| 150 | + const sellItems = useMemo(() => { |
| 151 | + const serverItems = sellHistory ?? (sellStatusQuery === 'ALL' ? sellAllHistory : undefined); |
| 152 | + if (sellStatusQuery !== 'ALL' && serverItems && serverItems.length === 0 && sellItemsForCount.length) { |
| 153 | + return filterTradeItems(sellItemsForCount, sellStatus); |
| 154 | + } |
| 155 | + const baseItems = serverItems ?? sellAllHistory ?? []; |
| 156 | + return baseItems.map((item) => mapSellHistoryItem(item)); |
| 157 | + }, [sellHistory, sellStatusQuery, sellAllHistory, sellItemsForCount, sellStatus, mapSellHistoryItem]); |
| 158 | + |
| 159 | + const buyStatusTabs = createStatusTabs(buyItemsForCount, { buying: '구매중', completed: '구매완료' }); |
| 160 | + const sellStatusTabs = createStatusTabs(sellItemsForCount, { buying: '판매중', completed: '판매완료' }); |
12 | 161 |
|
13 | | - const buyStatusTabs = createStatusTabs(BUY_ITEMS, { buying: '구매중', completed: '구매완료' }); |
14 | | - const sellStatusTabs = createStatusTabs(SELL_ITEMS, { buying: '판매중', completed: '판매완료' }); |
| 162 | + const favoriteProductItems = useMemo( |
| 163 | + () => wishlistPosts.map((item, index) => mapWishlistPostItem(item, index)), |
| 164 | + [wishlistPosts] |
| 165 | + ); |
| 166 | + const favoriteRepairItems = useMemo( |
| 167 | + () => wishlistShops.map((item, index) => mapWishlistShopItem(item, index)), |
| 168 | + [wishlistShops] |
| 169 | + ); |
15 | 170 |
|
16 | 171 | const favoriteTabs: FavoriteTabs = [ |
17 | | - { id: 'product', label: '상품', count: FAVORITE_PRODUCT_ITEMS.length }, |
18 | | - { id: 'repair', label: '수리점', count: FAVORITE_REPAIR_ITEMS.length }, |
| 172 | + { id: 'product', label: '상품', count: favoriteProductItems.length }, |
| 173 | + { id: 'repair', label: '수리점', count: favoriteRepairItems.length }, |
19 | 174 | ]; |
20 | 175 |
|
21 | | - const filteredBuyItems = filterTradeItems(BUY_ITEMS, buyStatus); |
22 | | - const filteredSellItems = filterTradeItems(SELL_ITEMS, sellStatus); |
| 176 | + const filteredBuyItems = filterTradeItems(buyItems, buyStatus); |
| 177 | + const filteredSellItems = filterTradeItems(sellItems, sellStatus); |
23 | 178 |
|
24 | 179 | const currentStatusTabs = activeTab === 'buy' ? buyStatusTabs : sellStatusTabs; |
25 | 180 | const currentStatus = activeTab === 'buy' ? buyStatus : sellStatus; |
@@ -60,7 +215,10 @@ export const useMyPageState = () => { |
60 | 215 | currentFilteredItems, |
61 | 216 |
|
62 | 217 | // Raw data |
63 | | - favoriteProductItems: FAVORITE_PRODUCT_ITEMS, |
64 | | - favoriteRepairItems: FAVORITE_REPAIR_ITEMS, |
| 218 | + profileData, |
| 219 | + buyItems, |
| 220 | + sellItems, |
| 221 | + favoriteProductItems, |
| 222 | + favoriteRepairItems, |
65 | 223 | }; |
66 | 224 | }; |
0 commit comments