Refactor uploadBudget module
Refactor the uploadBudget.ts file into smaller, more manageable modules to improve code readability and maintainability.
This commit is contained in:
@@ -1,5 +1,20 @@
|
||||
|
||||
// 예산 동기화 관련 모듈
|
||||
/**
|
||||
* 예산 동기화 관련 모듈
|
||||
* 모든 예산 관련 함수를 하나의 파일에서 내보냅니다.
|
||||
*/
|
||||
|
||||
// 예산 업로드 관련 함수
|
||||
export * from './uploadBudget';
|
||||
export * from './uploadMonthlyBudget';
|
||||
export * from './uploadCategoryBudgets';
|
||||
|
||||
// 예산 다운로드 관련 함수
|
||||
export * from './downloadBudget';
|
||||
|
||||
// 예산 추적 관련 함수
|
||||
export * from './modifiedBudgetsTracker';
|
||||
|
||||
// 타입 정의 및 유틸리티
|
||||
export * from './types';
|
||||
export * from './validators';
|
||||
|
||||
50
src/utils/sync/budget/types.ts
Normal file
50
src/utils/sync/budget/types.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
/**
|
||||
* 예산 동기화 관련 타입 정의
|
||||
*/
|
||||
|
||||
// 예산 데이터 타입
|
||||
export interface BudgetData {
|
||||
daily: BudgetPeriod;
|
||||
weekly: BudgetPeriod;
|
||||
monthly: BudgetPeriod;
|
||||
[key: string]: BudgetPeriod;
|
||||
}
|
||||
|
||||
// 기간별 예산 타입
|
||||
export interface BudgetPeriod {
|
||||
targetAmount: number;
|
||||
spentAmount: number;
|
||||
remainingAmount: number;
|
||||
[key: string]: number;
|
||||
}
|
||||
|
||||
// 카테고리 예산 타입
|
||||
export type CategoryBudgets = Record<string, number>;
|
||||
|
||||
// 예산 업로드 결과 타입
|
||||
export interface BudgetUploadResult {
|
||||
success: boolean;
|
||||
message: string;
|
||||
}
|
||||
|
||||
// 데이터베이스 예산 항목 타입
|
||||
export interface BudgetRecord {
|
||||
id?: string;
|
||||
user_id: string;
|
||||
month: number;
|
||||
year: number;
|
||||
total_budget: number;
|
||||
created_at?: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
// 데이터베이스 카테고리 예산 항목 타입
|
||||
export interface CategoryBudgetRecord {
|
||||
id?: string;
|
||||
user_id: string;
|
||||
category: string;
|
||||
amount: number;
|
||||
created_at?: string;
|
||||
updated_at: string;
|
||||
}
|
||||
@@ -1,10 +1,16 @@
|
||||
|
||||
import { supabase } from '@/lib/supabase';
|
||||
/**
|
||||
* 예산 데이터 업로드 메인 모듈
|
||||
*/
|
||||
import { isSyncEnabled } from '../syncSettings';
|
||||
import {
|
||||
clearModifiedBudget,
|
||||
clearModifiedCategoryBudgets
|
||||
} from './modifiedBudgetsTracker';
|
||||
import { uploadMonthlyBudget } from './uploadMonthlyBudget';
|
||||
import { uploadCategoryBudgets } from './uploadCategoryBudgets';
|
||||
import { isValidMonthlyBudget, isValidCategoryBudgets } from './validators';
|
||||
import { BudgetData, CategoryBudgets } from './types';
|
||||
|
||||
/**
|
||||
* 예산 데이터를 서버에 업로드
|
||||
@@ -20,35 +26,48 @@ export const uploadBudgets = async (userId: string): Promise<void> => {
|
||||
|
||||
// 예산 데이터 업로드
|
||||
if (budgetDataStr) {
|
||||
const budgetData = JSON.parse(budgetDataStr);
|
||||
try {
|
||||
const budgetData: BudgetData = JSON.parse(budgetDataStr);
|
||||
|
||||
// 월간 예산이 0보다 클 때만 업로드
|
||||
if (budgetData.monthly && typeof budgetData.monthly.targetAmount === 'number' && budgetData.monthly.targetAmount > 0) {
|
||||
// 월간 예산이 유효할 때만 업로드
|
||||
if (isValidMonthlyBudget(budgetData)) {
|
||||
console.log('유효한 월간 예산 발견:', budgetData.monthly.targetAmount);
|
||||
await uploadBudgetData(userId, budgetData);
|
||||
const uploadSuccess = await uploadMonthlyBudget(userId, budgetData);
|
||||
|
||||
// 업로드 성공 후 수정 추적 정보 초기화
|
||||
if (uploadSuccess) {
|
||||
clearModifiedBudget();
|
||||
}
|
||||
} else {
|
||||
console.log('월간 예산이 0 이하거나 없어서 업로드 건너뜀');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('월간 예산 데이터 파싱 또는 업로드 오류:', error);
|
||||
}
|
||||
} else {
|
||||
console.log('업로드할 예산 데이터가 없음');
|
||||
}
|
||||
|
||||
// 카테고리 예산 업로드
|
||||
if (categoryBudgetsStr) {
|
||||
const categoryBudgets = JSON.parse(categoryBudgetsStr);
|
||||
try {
|
||||
const categoryBudgets: CategoryBudgets = JSON.parse(categoryBudgetsStr);
|
||||
|
||||
// 총 카테고리 예산이 유효할 때만 업로드
|
||||
if (isValidCategoryBudgets(categoryBudgets)) {
|
||||
console.log('유효한 카테고리 예산 발견');
|
||||
const uploadSuccess = await uploadCategoryBudgets(userId, categoryBudgets);
|
||||
|
||||
// 총 카테고리 예산이 0보다 클 때만 업로드
|
||||
const totalCategoryBudget = Object.values(categoryBudgets).reduce((sum: number, val: number) => sum + val, 0);
|
||||
if (totalCategoryBudget > 0) {
|
||||
console.log('유효한 카테고리 예산 발견:', totalCategoryBudget);
|
||||
await uploadCategoryBudgets(userId, categoryBudgets);
|
||||
// 업로드 성공 후 수정 추적 정보 초기화
|
||||
if (uploadSuccess) {
|
||||
clearModifiedCategoryBudgets();
|
||||
}
|
||||
} else {
|
||||
console.log('카테고리 예산이 모두 0이어서 업로드 건너뜀');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('카테고리 예산 데이터 파싱 또는 업로드 오류:', error);
|
||||
}
|
||||
} else {
|
||||
console.log('업로드할 카테고리 예산이 없음');
|
||||
}
|
||||
@@ -59,171 +78,3 @@ export const uploadBudgets = async (userId: string): Promise<void> => {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 일반 예산 데이터 업로드
|
||||
*/
|
||||
async function uploadBudgetData(userId: string, parsedBudgetData: Record<string, any>): Promise<void> {
|
||||
console.log('예산 데이터 업로드:', parsedBudgetData);
|
||||
|
||||
// 현재 월/년도 가져오기
|
||||
const now = new Date();
|
||||
const currentMonth = now.getMonth() + 1; // 0-11 -> 1-12
|
||||
const currentYear = now.getFullYear();
|
||||
|
||||
// 기존 예산 데이터 확인
|
||||
const { data: existingBudgets, error: fetchError } = await supabase
|
||||
.from('budgets')
|
||||
.select('*')
|
||||
.eq('user_id', userId)
|
||||
.eq('month', currentMonth)
|
||||
.eq('year', currentYear);
|
||||
|
||||
if (fetchError) {
|
||||
console.error('기존 예산 데이터 조회 실패:', fetchError);
|
||||
throw fetchError;
|
||||
}
|
||||
|
||||
// 월간 타겟 금액 가져오기
|
||||
const monthlyTarget = parsedBudgetData.monthly.targetAmount;
|
||||
|
||||
// 예산이 0 이하면 업로드하지 않음
|
||||
if (typeof monthlyTarget !== 'number' || monthlyTarget <= 0) {
|
||||
console.log('월간 예산이 0 이하여서 업로드 건너뜀:', monthlyTarget);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('업로드할 월간 예산:', monthlyTarget);
|
||||
|
||||
// 현재 타임스탬프
|
||||
const currentTimestamp = new Date().toISOString();
|
||||
|
||||
// 가능한 경우 서버 데이터와 비교하여 필요한 경우만 업데이트
|
||||
if (existingBudgets && existingBudgets.length > 0) {
|
||||
const existingBudget = existingBudgets[0];
|
||||
// 새 예산이 기존 예산보다 클 때만 업데이트
|
||||
if (typeof existingBudget.total_budget === 'number' && monthlyTarget > existingBudget.total_budget) {
|
||||
console.log(`새 예산(${monthlyTarget})이 기존 예산(${existingBudget.total_budget})보다 큼, 업데이트 실행`);
|
||||
|
||||
// 기존 데이터 업데이트
|
||||
const { error } = await supabase
|
||||
.from('budgets')
|
||||
.update({
|
||||
total_budget: monthlyTarget,
|
||||
updated_at: currentTimestamp
|
||||
})
|
||||
.eq('id', existingBudget.id);
|
||||
|
||||
if (error) {
|
||||
console.error('예산 데이터 업데이트 실패:', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.log('예산 데이터 업데이트 성공');
|
||||
} else {
|
||||
console.log(`새 예산(${monthlyTarget})이 기존 예산(${existingBudget.total_budget})보다 작거나 같음, 업데이트 건너뜀`);
|
||||
}
|
||||
} else {
|
||||
// 새 데이터 삽입
|
||||
const { error } = await supabase
|
||||
.from('budgets')
|
||||
.insert({
|
||||
user_id: userId,
|
||||
month: currentMonth,
|
||||
year: currentYear,
|
||||
total_budget: monthlyTarget,
|
||||
created_at: currentTimestamp,
|
||||
updated_at: currentTimestamp
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error('예산 데이터 삽입 실패:', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.log('예산 데이터 삽입 성공');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 카테고리 예산 데이터 업로드
|
||||
*/
|
||||
async function uploadCategoryBudgets(userId: string, parsedCategoryBudgets: Record<string, number>): Promise<void> {
|
||||
console.log('카테고리 예산 업로드:', parsedCategoryBudgets);
|
||||
|
||||
// 기존 카테고리 예산 확인
|
||||
const { data: existingCategoryBudgets, error: fetchError } = await supabase
|
||||
.from('category_budgets')
|
||||
.select('*')
|
||||
.eq('user_id', userId);
|
||||
|
||||
if (fetchError) {
|
||||
console.error('기존 카테고리 예산 조회 실패:', fetchError);
|
||||
throw fetchError;
|
||||
}
|
||||
|
||||
// 기존 카테고리 예산의 총액 계산
|
||||
let existingTotal = 0;
|
||||
if (existingCategoryBudgets && existingCategoryBudgets.length > 0) {
|
||||
existingTotal = existingCategoryBudgets.reduce((sum, item) => {
|
||||
return sum + (typeof item.amount === 'number' ? item.amount : 0);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// 새 카테고리 예산의 총액 계산
|
||||
const newTotal = Object.values(parsedCategoryBudgets).reduce((sum: number, val: number) => sum + val, 0);
|
||||
|
||||
// 새 카테고리 예산 총액이 기존 카테고리 예산 총액보다 작거나 같으면 업로드 건너뜀
|
||||
if (newTotal <= existingTotal && existingTotal > 0) {
|
||||
console.log(`새 카테고리 예산 총액(${newTotal})이 기존 예산 총액(${existingTotal})보다 작거나 같음, 업로드 건너뜀`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 새 카테고리 예산 총액이 0이면 업로드 건너뜀
|
||||
if (newTotal <= 0) {
|
||||
console.log('새 카테고리 예산 총액이 0이하여서 업로드 건너뜀');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`새 카테고리 예산 총액(${newTotal})이 기존 예산 총액(${existingTotal})보다 큼, 업로드 실행`);
|
||||
|
||||
// 기존 카테고리 예산 삭제
|
||||
const { error: deleteError } = await supabase
|
||||
.from('category_budgets')
|
||||
.delete()
|
||||
.eq('user_id', userId);
|
||||
|
||||
if (deleteError) {
|
||||
console.error('기존 카테고리 예산 삭제 실패:', deleteError);
|
||||
// 오류가 나도 계속 진행 (중요 데이터가 아니기 때문)
|
||||
}
|
||||
|
||||
// 현재 타임스탬프
|
||||
const currentTimestamp = new Date().toISOString();
|
||||
|
||||
// 카테고리별 예산 데이터 변환 및 삽입
|
||||
const categoryEntries = Object.entries(parsedCategoryBudgets)
|
||||
.filter(([_, amount]) => typeof amount === 'number' && amount > 0) // 금액이 0보다 큰 것만 저장
|
||||
.map(([category, amount]) => ({
|
||||
user_id: userId,
|
||||
category,
|
||||
amount,
|
||||
created_at: currentTimestamp,
|
||||
updated_at: currentTimestamp
|
||||
}));
|
||||
|
||||
if (categoryEntries.length > 0) {
|
||||
const { error } = await supabase
|
||||
.from('category_budgets')
|
||||
.insert(categoryEntries);
|
||||
|
||||
if (error) {
|
||||
console.error('카테고리 예산 삽입 실패:', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.log('카테고리 예산 삽입 성공:', categoryEntries.length, '개');
|
||||
} else {
|
||||
console.log('저장할 카테고리 예산이 없음');
|
||||
}
|
||||
}
|
||||
|
||||
92
src/utils/sync/budget/uploadCategoryBudgets.ts
Normal file
92
src/utils/sync/budget/uploadCategoryBudgets.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
|
||||
/**
|
||||
* 카테고리 예산 업로드 기능
|
||||
*/
|
||||
import { supabase } from '@/lib/supabase';
|
||||
import { CategoryBudgets, CategoryBudgetRecord } from './types';
|
||||
import { calculateTotalCategoryBudget, filterValidCategoryBudgets } from './validators';
|
||||
|
||||
/**
|
||||
* 카테고리 예산 데이터 업로드
|
||||
*/
|
||||
export async function uploadCategoryBudgets(userId: string, parsedCategoryBudgets: CategoryBudgets): Promise<boolean> {
|
||||
console.log('카테고리 예산 업로드:', parsedCategoryBudgets);
|
||||
|
||||
// 기존 카테고리 예산 확인
|
||||
const { data: existingCategoryBudgets, error: fetchError } = await supabase
|
||||
.from('category_budgets')
|
||||
.select('*')
|
||||
.eq('user_id', userId);
|
||||
|
||||
if (fetchError) {
|
||||
console.error('기존 카테고리 예산 조회 실패:', fetchError);
|
||||
throw fetchError;
|
||||
}
|
||||
|
||||
// 기존 카테고리 예산의 총액 계산
|
||||
let existingTotal = 0;
|
||||
if (existingCategoryBudgets && existingCategoryBudgets.length > 0) {
|
||||
existingTotal = existingCategoryBudgets.reduce((sum, item) => {
|
||||
return sum + (typeof item.amount === 'number' ? item.amount : 0);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// 새 카테고리 예산의 총액 계산
|
||||
const newTotal = calculateTotalCategoryBudget(parsedCategoryBudgets);
|
||||
|
||||
// 새 카테고리 예산 총액이 기존 카테고리 예산 총액보다 작거나 같으면 업로드 건너뜀
|
||||
if (newTotal <= existingTotal && existingTotal > 0) {
|
||||
console.log(`새 카테고리 예산 총액(${newTotal})이 기존 예산 총액(${existingTotal})보다 작거나 같음, 업로드 건너뜀`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 새 카테고리 예산 총액이 0이면 업로드 건너뜀
|
||||
if (newTotal <= 0) {
|
||||
console.log('새 카테고리 예산 총액이 0이하여서 업로드 건너뜀');
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log(`새 카테고리 예산 총액(${newTotal})이 기존 예산 총액(${existingTotal})보다 큼, 업로드 실행`);
|
||||
|
||||
// 기존 카테고리 예산 삭제
|
||||
const { error: deleteError } = await supabase
|
||||
.from('category_budgets')
|
||||
.delete()
|
||||
.eq('user_id', userId);
|
||||
|
||||
if (deleteError) {
|
||||
console.error('기존 카테고리 예산 삭제 실패:', deleteError);
|
||||
// 오류가 나도 계속 진행 (중요 데이터가 아니기 때문)
|
||||
}
|
||||
|
||||
// 현재 타임스탬프
|
||||
const currentTimestamp = new Date().toISOString();
|
||||
|
||||
// 카테고리별 예산 데이터 변환 및 삽입
|
||||
const validCategoryBudgets = filterValidCategoryBudgets(parsedCategoryBudgets);
|
||||
const categoryEntries: CategoryBudgetRecord[] = Object.entries(validCategoryBudgets)
|
||||
.map(([category, amount]) => ({
|
||||
user_id: userId,
|
||||
category,
|
||||
amount,
|
||||
created_at: currentTimestamp,
|
||||
updated_at: currentTimestamp
|
||||
}));
|
||||
|
||||
if (categoryEntries.length > 0) {
|
||||
const { error } = await supabase
|
||||
.from('category_budgets')
|
||||
.insert(categoryEntries);
|
||||
|
||||
if (error) {
|
||||
console.error('카테고리 예산 삽입 실패:', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.log('카테고리 예산 삽입 성공:', categoryEntries.length, '개');
|
||||
return true;
|
||||
} else {
|
||||
console.log('저장할 카테고리 예산이 없음');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
98
src/utils/sync/budget/uploadMonthlyBudget.ts
Normal file
98
src/utils/sync/budget/uploadMonthlyBudget.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
|
||||
/**
|
||||
* 월간 예산 업로드 기능
|
||||
*/
|
||||
import { supabase } from '@/lib/supabase';
|
||||
import { BudgetData, BudgetRecord } from './types';
|
||||
import { isValidMonthlyBudget } from './validators';
|
||||
|
||||
/**
|
||||
* 월간 예산 데이터 업로드
|
||||
*/
|
||||
export async function uploadMonthlyBudget(userId: string, parsedBudgetData: BudgetData): Promise<boolean> {
|
||||
console.log('월간 예산 데이터 업로드:', parsedBudgetData);
|
||||
|
||||
// 월간 타겟 금액 가져오기
|
||||
const monthlyTarget = parsedBudgetData.monthly.targetAmount;
|
||||
|
||||
// 예산이 0 이하면 업로드하지 않음
|
||||
if (typeof monthlyTarget !== 'number' || monthlyTarget <= 0) {
|
||||
console.log('월간 예산이 0 이하여서 업로드 건너뜀:', monthlyTarget);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 현재 월/년도 가져오기
|
||||
const now = new Date();
|
||||
const currentMonth = now.getMonth() + 1; // 0-11 -> 1-12
|
||||
const currentYear = now.getFullYear();
|
||||
|
||||
// 기존 예산 데이터 확인
|
||||
const { data: existingBudgets, error: fetchError } = await supabase
|
||||
.from('budgets')
|
||||
.select('*')
|
||||
.eq('user_id', userId)
|
||||
.eq('month', currentMonth)
|
||||
.eq('year', currentYear);
|
||||
|
||||
if (fetchError) {
|
||||
console.error('기존 예산 데이터 조회 실패:', fetchError);
|
||||
throw fetchError;
|
||||
}
|
||||
|
||||
console.log('업로드할 월간 예산:', monthlyTarget);
|
||||
|
||||
// 현재 타임스탬프
|
||||
const currentTimestamp = new Date().toISOString();
|
||||
|
||||
// 가능한 경우 서버 데이터와 비교하여 필요한 경우만 업데이트
|
||||
if (existingBudgets && existingBudgets.length > 0) {
|
||||
const existingBudget = existingBudgets[0];
|
||||
|
||||
// 새 예산이 기존 예산보다 클 때만 업데이트
|
||||
if (typeof existingBudget.total_budget === 'number' && monthlyTarget > existingBudget.total_budget) {
|
||||
console.log(`새 예산(${monthlyTarget})이 기존 예산(${existingBudget.total_budget})보다 큼, 업데이트 실행`);
|
||||
|
||||
// 기존 데이터 업데이트
|
||||
const { error } = await supabase
|
||||
.from('budgets')
|
||||
.update({
|
||||
total_budget: monthlyTarget,
|
||||
updated_at: currentTimestamp
|
||||
})
|
||||
.eq('id', existingBudget.id);
|
||||
|
||||
if (error) {
|
||||
console.error('예산 데이터 업데이트 실패:', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.log('예산 데이터 업데이트 성공');
|
||||
return true;
|
||||
} else {
|
||||
console.log(`새 예산(${monthlyTarget})이 기존 예산(${existingBudget.total_budget})보다 작거나 같음, 업데이트 건너뜀`);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// 새 데이터 삽입
|
||||
const newBudget: BudgetRecord = {
|
||||
user_id: userId,
|
||||
month: currentMonth,
|
||||
year: currentYear,
|
||||
total_budget: monthlyTarget,
|
||||
created_at: currentTimestamp,
|
||||
updated_at: currentTimestamp
|
||||
};
|
||||
|
||||
const { error } = await supabase
|
||||
.from('budgets')
|
||||
.insert(newBudget);
|
||||
|
||||
if (error) {
|
||||
console.error('예산 데이터 삽입 실패:', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.log('예산 데이터 삽입 성공');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
50
src/utils/sync/budget/validators.ts
Normal file
50
src/utils/sync/budget/validators.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
/**
|
||||
* 예산 데이터 검증 유틸리티
|
||||
*/
|
||||
import { BudgetData, CategoryBudgets } from './types';
|
||||
|
||||
/**
|
||||
* 월간 예산이 유효한지 확인
|
||||
*/
|
||||
export const isValidMonthlyBudget = (budgetData: BudgetData | null): boolean => {
|
||||
if (!budgetData || !budgetData.monthly) return false;
|
||||
|
||||
const { targetAmount } = budgetData.monthly;
|
||||
return typeof targetAmount === 'number' && targetAmount > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* 카테고리 예산이 유효한지 확인
|
||||
*/
|
||||
export const isValidCategoryBudgets = (categoryBudgets: CategoryBudgets | null): boolean => {
|
||||
if (!categoryBudgets) return false;
|
||||
|
||||
// 총 예산 금액 계산
|
||||
const totalAmount = Object.values(categoryBudgets).reduce((sum, amount) => {
|
||||
return sum + (typeof amount === 'number' ? amount : 0);
|
||||
}, 0);
|
||||
|
||||
return totalAmount > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* 카테고리 예산 총액 계산
|
||||
*/
|
||||
export const calculateTotalCategoryBudget = (categoryBudgets: CategoryBudgets | null): number => {
|
||||
if (!categoryBudgets) return 0;
|
||||
|
||||
return Object.values(categoryBudgets).reduce((sum, amount) => {
|
||||
return sum + (typeof amount === 'number' ? amount : 0);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* 유효한 카테고리 예산 항목만 필터링
|
||||
*/
|
||||
export const filterValidCategoryBudgets = (categoryBudgets: CategoryBudgets): CategoryBudgets => {
|
||||
return Object.fromEntries(
|
||||
Object.entries(categoryBudgets)
|
||||
.filter(([_, amount]) => typeof amount === 'number' && amount > 0)
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user