diff --git a/package-lock.json b/package-lock.json index 2bd5006..a8fafc0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3844,9 +3844,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.267", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", - "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "version": "1.5.277", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.277.tgz", + "integrity": "sha512-wKXFZw4erWmmOz5N/grBoJ2XrNJGDFMu2+W5ACHza5rHtvsqrK4gb6rnLC7XxKB9WlJ+RmyQatuEXmtm86xbnw==", "dev": true, "license": "ISC" }, diff --git a/src/assets/icons/Add.svg b/src/assets/icons/Add.svg new file mode 100644 index 0000000..1112ae9 --- /dev/null +++ b/src/assets/icons/Add.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/menu/asset.svg b/src/assets/icons/menu/asset.svg new file mode 100644 index 0000000..12f0772 --- /dev/null +++ b/src/assets/icons/menu/asset.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/icons/menu/connection.svg b/src/assets/icons/menu/connection.svg new file mode 100644 index 0000000..aaf4962 --- /dev/null +++ b/src/assets/icons/menu/connection.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/icons/menu/goal.svg b/src/assets/icons/menu/goal.svg new file mode 100644 index 0000000..77cfefe --- /dev/null +++ b/src/assets/icons/menu/goal.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/menu/ledger.svg b/src/assets/icons/menu/ledger.svg new file mode 100644 index 0000000..ef33ce8 --- /dev/null +++ b/src/assets/icons/menu/ledger.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/icons/menu/mbti.svg b/src/assets/icons/menu/mbti.svg new file mode 100644 index 0000000..cc7ee2d --- /dev/null +++ b/src/assets/icons/menu/mbti.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/icons/menu/recommend.svg b/src/assets/icons/menu/recommend.svg new file mode 100644 index 0000000..f90054b --- /dev/null +++ b/src/assets/icons/menu/recommend.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/menu/setting.svg b/src/assets/icons/menu/setting.svg new file mode 100644 index 0000000..8082e36 --- /dev/null +++ b/src/assets/icons/menu/setting.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/menu/trophy.svg b/src/assets/icons/menu/trophy.svg new file mode 100644 index 0000000..ce5e661 --- /dev/null +++ b/src/assets/icons/menu/trophy.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/icons/warning.svg b/src/assets/icons/warning.svg new file mode 100644 index 0000000..abf7182 --- /dev/null +++ b/src/assets/icons/warning.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/components/common/BottomSheet.tsx b/src/components/common/BottomSheet.tsx index 2c38c4d..e552bce 100644 --- a/src/components/common/BottomSheet.tsx +++ b/src/components/common/BottomSheet.tsx @@ -43,4 +43,4 @@ const BottomSheet = ({ isOpen, onClose, title, children }: BottomSheetProps) => ); }; -export default BottomSheet; \ No newline at end of file +export default BottomSheet; diff --git a/src/components/common/Toast.tsx b/src/components/common/Toast.tsx new file mode 100644 index 0000000..b20b757 --- /dev/null +++ b/src/components/common/Toast.tsx @@ -0,0 +1,29 @@ +// src/components/common/Toast.tsx +import { Typography } from '@/components/typography'; +import WarningIcon from '@/assets/icons/warning.svg'; +import { cn } from '@/utils/cn'; + +export const Toast = ({ message, isOpen }: { message: string; isOpen: boolean }) => { + if (!isOpen) return null; + + return ( +
+
+ 경고 + + + {message} + +
+
+ ); +}; diff --git a/src/components/goal/GoalBottonSheet.tsx b/src/components/goal/GoalBottonSheet.tsx index 5616214..9d4ea6c 100644 --- a/src/components/goal/GoalBottonSheet.tsx +++ b/src/components/goal/GoalBottonSheet.tsx @@ -30,21 +30,13 @@ const GoalBottomSheet = ({ isOpen, item, onClose }: GoalBottomSheetProps) => { placeholder="메모를 남겨주세요 (최대 20자)" className="w-full text-base outline-none placeholder:text-gray-400" /> - edit memo + edit memo
- +
diff --git a/src/components/goal/GoalGNB.tsx b/src/components/goal/GoalGNB.tsx index d4259eb..6e985dd 100644 --- a/src/components/goal/GoalGNB.tsx +++ b/src/components/goal/GoalGNB.tsx @@ -25,9 +25,7 @@ const GoalGNB = () => { +); + +/** + * 💡 메뉴 섹션 (자산, 목표 등 그룹) + */ +const MenuSection = ({ title, children, icon }: { title: string; children: React.ReactNode; icon: string }) => ( +
+ {' '} + {/* 💡 border-b 대신 border-t 사용! */} +
+ {title} + + {title} + +
+
{children}
+
+); + +/** + * 💡 MenuItem: div로 감싸서 중첩 버튼 에러 해결 + */ +const MenuItem = ({ label, onClick }: { label: string; onClick?: () => void }) => ( +
+ + {label} + + +
+); diff --git a/src/features/asset/constants/account.ts b/src/features/asset/constants/account.ts index c5c255f..ee6e239 100644 --- a/src/features/asset/constants/account.ts +++ b/src/features/asset/constants/account.ts @@ -32,4 +32,4 @@ export interface TransactionGroup { totalIncome: number; totalExpense: number; items: TransactionItem[]; -} \ No newline at end of file +} diff --git a/src/features/asset/constants/category.ts b/src/features/asset/constants/category.ts index 3dd514d..374985d 100644 --- a/src/features/asset/constants/category.ts +++ b/src/features/asset/constants/category.ts @@ -44,4 +44,4 @@ export const CATEGORY_STYLES: Record = { living: { bgColor: 'bg-atomic-purple-90', barColor: 'bg-atomic-purple-50', icon: LivingIcon }, // 주거 cafe: { bgColor: 'bg-atomic-green-90', barColor: 'bg-atomic-green-50', icon: CafeIcon }, // 카페 others: { bgColor: 'bg-neutral-60', barColor: 'bg-neutral-80', icon: OthersIcon }, // 그외 -}; \ No newline at end of file +}; diff --git a/src/hooks/Asset/useGetAccountDetail.ts b/src/hooks/Asset/useGetAccountDetail.ts index ee3e12c..2887367 100644 --- a/src/hooks/Asset/useGetAccountDetail.ts +++ b/src/hooks/Asset/useGetAccountDetail.ts @@ -103,4 +103,4 @@ export const useGetAccountDetail = () => { transactionHistory: mockHistory, totalCount: 10, }; -}; \ No newline at end of file +}; diff --git a/src/hooks/Asset/useGetAssetAnalysis.ts b/src/hooks/Asset/useGetAssetAnalysis.ts index d0e8a71..23a9557 100644 --- a/src/hooks/Asset/useGetAssetAnalysis.ts +++ b/src/hooks/Asset/useGetAssetAnalysis.ts @@ -26,22 +26,17 @@ export const useGetAssetAnalysis = (selectedDate: Date = new Date()) => { return ASSET_ANALYSIS_RAW_DATA.filter((item) => { const itemDate = new Date(item.date); - return ( - itemDate.getFullYear() === targetYear && - itemDate.getMonth() === targetMonth - ); + return itemDate.getFullYear() === targetYear && itemDate.getMonth() === targetMonth; }); }, [selectedDate]); // 💡 4. 상세 정보를 포함한 트랜잭션 데이터 가공 const mockTransactions = useMemo((): TransactionWithDetails[] => { - // 임시 시작 잔액 - let tempBalance = 5230450; + let tempBalance = 5230450; // 초기 잔액 설정 return filteredData.map((item) => { const simpleType = item.sub.includes('|') ? item.sub.split('|')[1].trim() : item.sub; const currentBalance = tempBalance; tempBalance -= item.amount; // 다음 아이템을 위해 역산 (리스트가 최신순일 경우) - return { ...item, displayDetails: [ @@ -58,9 +53,7 @@ export const useGetAssetAnalysis = (selectedDate: Date = new Date()) => { // 💡 5. 총 지출액 계산 const totalExpense = useMemo( () => - mockTransactions - .filter((item) => item.type === 'expense') - .reduce((sum, item) => sum + Math.abs(item.amount), 0), + mockTransactions.filter((item) => item.type === 'expense').reduce((sum, item) => sum + Math.abs(item.amount), 0), [mockTransactions] ); @@ -80,4 +73,4 @@ export const useGetAssetAnalysis = (selectedDate: Date = new Date()) => { otherCount: Math.max(0, allSectors.length - 6), otherTotalAmount: allSectors.slice(6).reduce((sum, s) => sum + s.amount, 0), }; -}; \ No newline at end of file +}; diff --git a/src/pages/Asset/AssetPage.tsx b/src/pages/Asset/AssetPage.tsx index c5c4f3e..34bc327 100644 --- a/src/pages/Asset/AssetPage.tsx +++ b/src/pages/Asset/AssetPage.tsx @@ -1,4 +1,3 @@ -import { useState } from 'react'; import { MobileLayout } from '@/components/layout/MobileLayout'; import { HomeGNB } from '@/components/gnb/HomeGNB'; import { BottomNavigation } from '@/components/gnb/BottomNavigation'; @@ -14,8 +13,7 @@ export const AssetPage = () => { const navigate = useNavigate(); const { pathname } = useLocation(); - const activeTab = pathname.includes('/sector') ? 'sector' : - pathname.includes('/compare') ? 'compare' : 'details'; + const activeTab = pathname.includes('/sector') ? 'sector' : pathname.includes('/compare') ? 'compare' : 'details'; const handleTabClick = (tab: 'details' | 'sector' | 'compare') => { if (tab === 'details') navigate('/asset'); @@ -23,20 +21,7 @@ export const AssetPage = () => { }; const handleNavClick = (item: 'home' | 'asset' | 'recommend' | 'goal') => { - switch (item) { - case 'home': - navigate('/home'); - break; - case 'asset': - navigate('/asset'); - break; - case 'recommend': - navigate('/recommend'); - break; - case 'goal': - navigate('/goal'); - break; - } + navigate(`/${item}`); }; return ( @@ -99,4 +84,4 @@ export const AssetPage = () => { ); }; -export default AssetPage; \ No newline at end of file +export default AssetPage; diff --git a/src/pages/Asset/tab/AssetDetails/components/AssetLedger.tsx b/src/pages/Asset/tab/AssetDetails/components/AssetLedger.tsx index bb9ee42..e00b806 100644 --- a/src/pages/Asset/tab/AssetDetails/components/AssetLedger.tsx +++ b/src/pages/Asset/tab/AssetDetails/components/AssetLedger.tsx @@ -80,4 +80,4 @@ export const AssetLedger = () => { {viewMode === 'list' ? : } ); -}; \ No newline at end of file +}; diff --git a/src/pages/Asset/tab/AssetDetails/components/AssetList.tsx b/src/pages/Asset/tab/AssetDetails/components/AssetList.tsx index fcc1913..3b8ced4 100644 --- a/src/pages/Asset/tab/AssetDetails/components/AssetList.tsx +++ b/src/pages/Asset/tab/AssetDetails/components/AssetList.tsx @@ -150,4 +150,4 @@ export const AssetList = () => { ); -}; \ No newline at end of file +}; diff --git a/src/pages/Asset/tab/CompareAnalysis/CompareAnalysisPage.tsx b/src/pages/Asset/tab/CompareAnalysis/CompareAnalysisPage.tsx index 86a543e..3d856f4 100644 --- a/src/pages/Asset/tab/CompareAnalysis/CompareAnalysisPage.tsx +++ b/src/pages/Asset/tab/CompareAnalysis/CompareAnalysisPage.tsx @@ -19,20 +19,18 @@ export const CompareAnalysis = () => { return (
- {/* 1. 또래별 비교 섹션 */} - +
- + {/* 2. 카테고리별 비교 섹션 */}
- {/* 3. 소비내역 비교 섹션 */}
); -}; \ No newline at end of file +}; diff --git a/src/pages/Asset/tab/CompareAnalysis/components/CategoryCompareSection.tsx b/src/pages/Asset/tab/CompareAnalysis/components/CategoryCompareSection.tsx index 4102efd..e3fd362 100644 --- a/src/pages/Asset/tab/CompareAnalysis/components/CategoryCompareSection.tsx +++ b/src/pages/Asset/tab/CompareAnalysis/components/CategoryCompareSection.tsx @@ -10,11 +10,11 @@ import { CompareBarSkeleton } from './CompareBarSkeleton'; // 💡 2. 추가 const DISPLAY_NAMES: Record = { traffic: '교통', - transfer: '금융', food: '식비', living: '주거/통신', shopping: '쇼핑', leisure: '문화생활', + transfer: '이체', }; const TARGET_CATEGORIES = Object.keys(DISPLAY_NAMES); @@ -65,30 +65,28 @@ export const CategoryCompareSection = ({ isLoading = false }: CategoryCompareSec ref={scrollRef} className="flex gap-2 mb-10 overflow-x-auto pb-1 no-scrollbar scroll-smooth [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden" > - {isLoading ? ( - // 로딩 중일 땐 칩 모양 스켈레톤 5개 표시 ㅋ - Array.from({ length: 5 }).map((_, idx) => ( - - )) - ) : ( - TARGET_CATEGORIES.map((catKey) => { - const isSelected = selectedCategory === catKey; - return ( - - ); - }) - )} + {isLoading + ? // 로딩 중일 땐 칩 모양 스켈레톤 5개 표시 + Array.from({ length: 5 }).map((_, idx) => ( + + )) + : TARGET_CATEGORIES.map((catKey) => { + const isSelected = selectedCategory === catKey; + return ( + + ); + })}
{/* 💡 5. 바 차트 영역 로딩 처리 */} @@ -119,22 +117,36 @@ export const CategoryCompareSection = ({ isLoading = false }: CategoryCompareSec
{isLoading ? ( <> -
-
+
+ + +
+
+ + +
) : ( <>
- 내 소비 - {formatCurrency(myCategoryTotal)} + + 내 소비 + + + {formatCurrency(myCategoryTotal)} +
- 또래 평균 - {formatCurrency(peerCategoryTotal)} + + 또래 평균 + + + {formatCurrency(peerCategoryTotal)} +
)}
); -}; \ No newline at end of file +}; diff --git a/src/pages/Asset/tab/CompareAnalysis/components/HistoryCompareSection.tsx b/src/pages/Asset/tab/CompareAnalysis/components/HistoryCompareSection.tsx index fda2df1..a3368e2 100644 --- a/src/pages/Asset/tab/CompareAnalysis/components/HistoryCompareSection.tsx +++ b/src/pages/Asset/tab/CompareAnalysis/components/HistoryCompareSection.tsx @@ -50,11 +50,9 @@ export const HistoryCompareSection = ({ isLoading = false }: HistoryCompareSecti - ) : ( <> - @@ -63,4 +61,4 @@ export const HistoryCompareSection = ({ isLoading = false }: HistoryCompareSecti
); -}; \ No newline at end of file +}; diff --git a/src/pages/Asset/tab/CompareAnalysis/components/PeerCompareSection.tsx b/src/pages/Asset/tab/CompareAnalysis/components/PeerCompareSection.tsx index acc2b7d..210cfa8 100644 --- a/src/pages/Asset/tab/CompareAnalysis/components/PeerCompareSection.tsx +++ b/src/pages/Asset/tab/CompareAnalysis/components/PeerCompareSection.tsx @@ -58,4 +58,4 @@ export const PeerCompareSection = ({ isLoading = false }: PeerCompareSectionProp ); -}; \ No newline at end of file +}; diff --git a/src/pages/Asset/tab/SectorAnalysis/SectorAnalysisPage.tsx b/src/pages/Asset/tab/SectorAnalysis/SectorAnalysisPage.tsx index cecd91d..f84c347 100644 --- a/src/pages/Asset/tab/SectorAnalysis/SectorAnalysisPage.tsx +++ b/src/pages/Asset/tab/SectorAnalysis/SectorAnalysisPage.tsx @@ -8,7 +8,7 @@ import { transformToCategoryGroups } from './utils/sectorUtils'; export const SectorAnalysis = () => { const location = useLocation(); - + // 선택된 날짜 상태 관리 const [selectedDate, setSelectedDate] = useState( location.state?.selectedDate ? new Date(location.state.selectedDate) : new Date() @@ -25,8 +25,8 @@ export const SectorAnalysis = () => { const sectorData = transformToCategoryGroups(transactions, totalExpense); // 💡 2. 지난달 데이터 가져오기 (지출 차액 계산용) - const lastMonthDate = useMemo(() => - new Date(selectedDate.getFullYear(), selectedDate.getMonth() - 1, 1), + const lastMonthDate = useMemo( + () => new Date(selectedDate.getFullYear(), selectedDate.getMonth() - 1, 1), [selectedDate] ); const { totalExpense: lastMonthTotal } = useGetAssetAnalysis(lastMonthDate); @@ -54,15 +54,15 @@ export const SectorAnalysis = () => { isMore={isMore} isLoading={isLoading} // 💡 isLoading 전달! /> - + {/* 하단 리스트 섹션 (지출 상세) */} {/* 💡 SectorListSection 내부 인터페이스에 isLoading? 추가하셔야 빨간줄 사라져요! */} -
); -}; \ No newline at end of file +}; diff --git a/src/pages/Asset/tab/SectorAnalysis/SectorDetailPage.tsx b/src/pages/Asset/tab/SectorAnalysis/SectorDetailPage.tsx index 3b3f978..d9f3c36 100644 --- a/src/pages/Asset/tab/SectorAnalysis/SectorDetailPage.tsx +++ b/src/pages/Asset/tab/SectorAnalysis/SectorDetailPage.tsx @@ -58,9 +58,9 @@ export const SectorDetailPage = () => { { - navigate('/asset/sector', { - state: { selectedDate: selectedDate.toISOString() }, - replace: true // 히스토리가 중복으로 쌓이지 않게 교체 + navigate('/asset/sector', { + state: { selectedDate: selectedDate.toISOString() }, + replace: true, // 히스토리가 중복으로 쌓이지 않게 교체 }); }} text="" diff --git a/src/pages/Asset/tab/SectorAnalysis/components/SectorChartSkeleton.tsx b/src/pages/Asset/tab/SectorAnalysis/components/SectorChartSkeleton.tsx index 3cac629..e6888ca 100644 --- a/src/pages/Asset/tab/SectorAnalysis/components/SectorChartSkeleton.tsx +++ b/src/pages/Asset/tab/SectorAnalysis/components/SectorChartSkeleton.tsx @@ -1,15 +1,10 @@ import { Skeleton } from '@/components/skeleton/Skeleton'; - - export const SectorChartSkeleton = () => { - return ( - // 실제 차트 컨테이너와 동일한 구조
- {/* 비율이 다른 막대 3~4개를 배치 */} @@ -21,9 +16,6 @@ export const SectorChartSkeleton = () => { -
- ); - -}; \ No newline at end of file +}; diff --git a/src/pages/Asset/tab/SectorAnalysis/components/TransactionDetailModal.tsx b/src/pages/Asset/tab/SectorAnalysis/components/TransactionDetailModal.tsx index 449869c..1f761b0 100644 --- a/src/pages/Asset/tab/SectorAnalysis/components/TransactionDetailModal.tsx +++ b/src/pages/Asset/tab/SectorAnalysis/components/TransactionDetailModal.tsx @@ -15,8 +15,8 @@ export const TransactionDetailModal = ({ item, onClose }: TransactionDetailModal if (!item) return null; return ( - diff --git a/src/pages/Asset/tab/SectorAnalysis/sections/SectorListSection.tsx b/src/pages/Asset/tab/SectorAnalysis/sections/SectorListSection.tsx index 5819640..94f5887 100644 --- a/src/pages/Asset/tab/SectorAnalysis/sections/SectorListSection.tsx +++ b/src/pages/Asset/tab/SectorAnalysis/sections/SectorListSection.tsx @@ -10,10 +10,10 @@ interface SectorListSectionProps { selectedDate: Date; } -export const SectorListSection = ({ - data, +export const SectorListSection = ({ + data, isLoading = false, // 💡 3. props에서 꺼내기 - selectedDate + selectedDate, }: SectorListSectionProps) => { const navigate = useNavigate(); @@ -49,7 +49,9 @@ export const SectorListSection = ({ data={{ ...item, percentage: Math.floor(item.percentage) }} label={CATEGORY_LABELS[item.key] || CATEGORY_LABELS.default} onClick={() => { - navigate(`/asset/sector/${item.key}`, { state: { sectorData: item, selectedDate: selectedDate.toISOString() } }); + navigate(`/asset/sector/${item.key}`, { + state: { sectorData: item, selectedDate: selectedDate.toISOString() }, + }); }} /> ))} @@ -65,7 +67,11 @@ export const SectorListSection = ({ items: [], }} label={`그외 ${otherCount}개`} - onClick={() => navigate('/asset/sector-full', { state: { filter: 'others', selectedDate: selectedDate.toISOString() } })} + onClick={() => + navigate('/asset/sector-full', { + state: { filter: 'others', selectedDate: selectedDate.toISOString() }, + }) + } /> )} @@ -73,4 +79,4 @@ export const SectorListSection = ({ ); -}; \ No newline at end of file +}; diff --git a/src/pages/Asset/tab/SectorAnalysis/sections/SectorSummarySection.tsx b/src/pages/Asset/tab/SectorAnalysis/sections/SectorSummarySection.tsx index 555358c..3d53379 100644 --- a/src/pages/Asset/tab/SectorAnalysis/sections/SectorSummarySection.tsx +++ b/src/pages/Asset/tab/SectorAnalysis/sections/SectorSummarySection.tsx @@ -47,11 +47,15 @@ export const SectorSummarySection = ({
{/* 📅 날짜 선택 */}
- + {monthDisplay} - +
{/* 💰 이번 달 총 지출 금액 섹션 */} @@ -82,12 +86,8 @@ export const SectorSummarySection = ({ {/* 📊 차트 섹션 */}
{/* 💡 5. 로딩 중일 때는 차트 대신 아까 만든 차트 스켈레톤 표시! */} - {isLoading ? ( - - ) : ( - - )} + {isLoading ? : }
); -}; \ No newline at end of file +}; diff --git a/src/pages/Goal/CurrentGoalPage.tsx b/src/pages/Goal/CurrentGoalPage.tsx index 1156eb7..aee82f5 100644 --- a/src/pages/Goal/CurrentGoalPage.tsx +++ b/src/pages/Goal/CurrentGoalPage.tsx @@ -43,15 +43,15 @@ export const CurrentGoalPage = () => { {/* 정렬 필터 UI */}
- · -