Refactor budgetUtils.ts

Refactor budgetUtils.ts to improve code organization and maintainability by splitting the logic into multiple files. The functionality remains the same.
This commit is contained in:
gpt-engineer-app[bot]
2025-03-22 10:59:57 +00:00
parent d5ac14793b
commit 8aabb2fa9c
7 changed files with 317 additions and 278 deletions

View File

@@ -0,0 +1,78 @@
import { BudgetData, BudgetPeriod } from '../types';
import { getInitialBudgetData } from './constants';
// 예산 데이터 업데이트 계산
export const calculateUpdatedBudgetData = (
prevBudgetData: BudgetData,
type: BudgetPeriod,
amount: number
): BudgetData => {
console.log(`예산 업데이트 계산 시작: 타입=${type}, 금액=${amount}`);
// 값이 없거나 유효하지 않은 경우 로깅
if (!prevBudgetData) {
console.error('이전 예산 데이터가 없습니다. 기본값 사용.');
prevBudgetData = getInitialBudgetData();
}
// 선택된 타입에 따라 다른 타입의 예산도 자동으로 계산
let monthlyAmount: number, weeklyAmount: number, dailyAmount: number;
if (type === 'monthly') {
// 월간 예산이 직접 입력된 경우
monthlyAmount = amount;
// 월 30일 기준 (실제 사용 시 값 확인)
dailyAmount = Math.round(monthlyAmount / 30);
// 월 4.3주 기준 (실제 사용 시 값 확인)
weeklyAmount = Math.round(monthlyAmount / 4.3);
} else if (type === 'weekly') {
// 주간 예산이 직접 입력된 경우
weeklyAmount = amount;
monthlyAmount = Math.round(weeklyAmount * 4.3);
dailyAmount = Math.round(weeklyAmount / 7);
} else { // 'daily'
// 일일 예산이 직접 입력된 경우
dailyAmount = amount;
weeklyAmount = Math.round(dailyAmount * 7);
monthlyAmount = Math.round(dailyAmount * 30);
}
// 모든 금액이 최소한 0 이상이 되도록 보장
monthlyAmount = Math.max(0, monthlyAmount);
weeklyAmount = Math.max(0, weeklyAmount);
dailyAmount = Math.max(0, dailyAmount);
console.log(`최종 예산 계산 결과: 월간=${monthlyAmount}원, 주간=${weeklyAmount}원, 일일=${dailyAmount}`);
// 로그에 이전 예산 데이터 출력
console.log("이전 예산 데이터:", JSON.stringify(prevBudgetData));
// 이전 지출 데이터 보존
const dailySpent = prevBudgetData.daily?.spentAmount || 0;
const weeklySpent = prevBudgetData.weekly?.spentAmount || 0;
const monthlySpent = prevBudgetData.monthly?.spentAmount || 0;
// 새 예산 데이터 생성 (spentAmount는 이전 값 유지)
const updatedBudgetData = {
daily: {
targetAmount: dailyAmount,
spentAmount: dailySpent,
remainingAmount: Math.max(0, dailyAmount - dailySpent)
},
weekly: {
targetAmount: weeklyAmount,
spentAmount: weeklySpent,
remainingAmount: Math.max(0, weeklyAmount - weeklySpent)
},
monthly: {
targetAmount: monthlyAmount,
spentAmount: monthlySpent,
remainingAmount: Math.max(0, monthlyAmount - monthlySpent)
}
};
console.log("새 예산 데이터:", JSON.stringify(updatedBudgetData));
return updatedBudgetData;
};

View File

@@ -0,0 +1,48 @@
import { CategoryBudget, Transaction } from '../types';
import { EXPENSE_CATEGORIES } from '@/constants/categoryIcons';
// 카테고리별 지출 계산
export const calculateCategorySpending = (
transactions: Transaction[],
categoryBudgets: Record<string, number>
): CategoryBudget[] => {
const expenseTransactions = transactions.filter(t => t.type === 'expense');
const categorySpending: Record<string, number> = {};
// 모든 카테고리에 대해 초기값 0 설정
Object.keys(categoryBudgets).forEach(category => {
// 정의된 카테고리만 유지
if (EXPENSE_CATEGORIES.includes(category)) {
categorySpending[category] = 0;
}
});
// 지원되는 카테고리가 없을 경우 기본값 설정
if (Object.keys(categorySpending).length === 0) {
EXPENSE_CATEGORIES.forEach(category => {
categorySpending[category] = 0;
});
}
expenseTransactions.forEach(t => {
if (t.category in categorySpending) {
categorySpending[t.category] += t.amount;
} else if (EXPENSE_CATEGORIES.includes(t.category)) {
// 지원되는 카테고리이지만 초기화되지 않은 경우
categorySpending[t.category] = t.amount;
} else if (t.category === '교통비') {
// 예전 카테고리명 '교통비'를 '교통'으로 매핑
categorySpending['교통'] = (categorySpending['교통'] || 0) + t.amount;
} else {
// 지원되지 않는 카테고리는 '기타'로 집계
categorySpending['기타'] = (categorySpending['기타'] || 0) + t.amount;
}
});
return EXPENSE_CATEGORIES.map(category => ({
title: category,
current: categorySpending[category] || 0,
total: categoryBudgets[category] || 0
}));
};

View File

@@ -0,0 +1,33 @@
import { BudgetData } from '../types';
// 기본 데이터 상수 (기본값을 0으로 설정)
export const DEFAULT_CATEGORY_BUDGETS: Record<string, number> = {
음식: 0,
쇼핑: 0,
교통: 0,
기타: 0
};
export const DEFAULT_MONTHLY_BUDGET = 0;
// 초기 예산 데이터 생성
export const getInitialBudgetData = (): BudgetData => {
return {
daily: {
targetAmount: 0,
spentAmount: 0,
remainingAmount: 0
},
weekly: {
targetAmount: 0,
spentAmount: 0,
remainingAmount: 0
},
monthly: {
targetAmount: 0,
spentAmount: 0,
remainingAmount: 0
}
};
};

View File

@@ -0,0 +1,58 @@
import { BudgetData, Transaction } from '../types';
// 지출액 계산 (일일, 주간, 월간)
export const calculateSpentAmounts = (
transactions: Transaction[],
prevBudgetData: BudgetData
): BudgetData => {
console.log("지출액 계산 시작, 트랜잭션 수:", transactions.length);
// 지출 거래 필터링
const expenseTransactions = transactions.filter(t => t.type === 'expense');
// 오늘 지출 계산
const todayExpenses = expenseTransactions.filter(t => {
if (t.date.includes('오늘')) return true;
return false;
});
const dailySpent = todayExpenses.reduce((sum, t) => sum + t.amount, 0);
// 이번 주 지출 계산 (단순화된 버전)
const weeklyExpenses = expenseTransactions.filter(t => {
if (t.date.includes('오늘') || t.date.includes('어제') || t.date.includes('이번주')) return true;
return true;
});
const weeklySpent = weeklyExpenses.reduce((sum, t) => sum + t.amount, 0);
// 이번 달 총 지출 계산
const monthlySpent = expenseTransactions.reduce((sum, t) => sum + t.amount, 0);
// 기존 예산 목표 유지 (없으면 기본값 0)
const dailyTarget = prevBudgetData?.daily?.targetAmount || 0;
const weeklyTarget = prevBudgetData?.weekly?.targetAmount || 0;
const monthlyTarget = prevBudgetData?.monthly?.targetAmount || 0;
// 예산 데이터 업데이트
const updatedBudget = {
daily: {
targetAmount: dailyTarget,
spentAmount: dailySpent,
remainingAmount: Math.max(0, dailyTarget - dailySpent)
},
weekly: {
targetAmount: weeklyTarget,
spentAmount: weeklySpent,
remainingAmount: Math.max(0, weeklyTarget - weeklySpent)
},
monthly: {
targetAmount: monthlyTarget,
spentAmount: monthlySpent,
remainingAmount: Math.max(0, monthlyTarget - monthlySpent)
}
};
console.log("지출액 계산 결과:", updatedBudget);
return updatedBudget;
};

View File

@@ -0,0 +1,65 @@
import { BudgetData } from '../types';
import { getInitialBudgetData } from './constants';
import { toast } from '@/hooks/useToast.wrapper';
// 스토리지에서 안전하게 예산 데이터 가져오기
export const safelyLoadBudgetData = (defaultData: BudgetData = getInitialBudgetData()): BudgetData => {
try {
const budgetDataStr = localStorage.getItem('budgetData');
if (budgetDataStr) {
const parsed = JSON.parse(budgetDataStr);
// 데이터 구조 검증 (daily, weekly, monthly 키 존재 확인)
if (parsed && parsed.daily && parsed.weekly && parsed.monthly) {
return parsed;
} else {
console.warn('저장된 예산 데이터 구조가 유효하지 않습니다. 기본값 사용.');
}
}
} catch (error) {
console.error('예산 데이터 로드 오류:', error);
}
// 오류 발생 또는 데이터 없음 시 기본값 반환
return defaultData;
};
// 안전한 스토리지 접근
export const safeStorage = {
get: (key: string, defaultValue: any = null): any => {
try {
const value = localStorage.getItem(key);
if (value === null) return defaultValue;
return JSON.parse(value);
} catch (error) {
console.error(`스토리지 읽기 오류 (${key}):`, error);
return defaultValue;
}
},
set: (key: string, value: any): boolean => {
try {
localStorage.setItem(key, JSON.stringify(value));
return true;
} catch (error) {
console.error(`스토리지 쓰기 오류 (${key}):`, error);
toast({
title: "저장 오류",
description: "데이터를 저장하는 중 문제가 발생했습니다.",
variant: "destructive"
});
return false;
}
},
remove: (key: string): boolean => {
try {
localStorage.removeItem(key);
return true;
} catch (error) {
console.error(`스토리지 삭제 오류 (${key}):`, error);
return false;
}
}
};