From d74acdbbb8b2a4c2ff11c8496a46a8149dec8bff Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 05:12:43 +0000 Subject: [PATCH] Refactor syncUtils module Refactor the syncUtils module to improve code organization and maintainability by breaking it down into smaller, more focused utility functions. --- src/utils/sync/budgetSync.ts | 127 ++++++++++++++++++ src/utils/sync/syncSettings.ts | 16 +++ src/utils/sync/transactionSync.ts | 76 +++++++++++ src/utils/syncUtils.ts | 213 ++---------------------------- 4 files changed, 233 insertions(+), 199 deletions(-) create mode 100644 src/utils/sync/budgetSync.ts create mode 100644 src/utils/sync/syncSettings.ts create mode 100644 src/utils/sync/transactionSync.ts diff --git a/src/utils/sync/budgetSync.ts b/src/utils/sync/budgetSync.ts new file mode 100644 index 0000000..6a693da --- /dev/null +++ b/src/utils/sync/budgetSync.ts @@ -0,0 +1,127 @@ + +import { supabase } from '@/lib/supabase'; +import { isSyncEnabled } from './syncSettings'; + +/** + * Upload budget data from local storage to Supabase + */ +export const uploadBudgets = async (userId: string): Promise => { + if (!isSyncEnabled()) return; + + try { + const budgetData = localStorage.getItem('budgetData'); + const categoryBudgets = localStorage.getItem('categoryBudgets'); + + if (budgetData) { + const parsedBudgetData = JSON.parse(budgetData); + + // 기존 예산 데이터 삭제 + await supabase + .from('budgets') + .delete() + .eq('user_id', userId); + + // 새 예산 데이터 삽입 + const { error } = await supabase.from('budgets').insert({ + user_id: userId, + daily_target: parsedBudgetData.daily.targetAmount, + weekly_target: parsedBudgetData.weekly.targetAmount, + monthly_target: parsedBudgetData.monthly.targetAmount + }); + + if (error) throw error; + } + + if (categoryBudgets) { + const parsedCategoryBudgets = JSON.parse(categoryBudgets); + + // 기존 카테고리 예산 삭제 + await supabase + .from('category_budgets') + .delete() + .eq('user_id', userId); + + // 카테고리별 예산 데이터 변환 및 삽입 + const categoryEntries = Object.entries(parsedCategoryBudgets).map( + ([category, amount]) => ({ + user_id: userId, + category, + amount + }) + ); + + const { error } = await supabase + .from('category_budgets') + .insert(categoryEntries); + + if (error) throw error; + } + + console.log('예산 데이터 업로드 완료'); + } catch (error) { + console.error('예산 데이터 업로드 실패:', error); + } +}; + +/** + * Download budget data from Supabase to local storage + */ +export const downloadBudgets = async (userId: string): Promise => { + if (!isSyncEnabled()) return; + + try { + // 예산 데이터 가져오기 + const { data: budgetData, error: budgetError } = await supabase + .from('budgets') + .select('*') + .eq('user_id', userId) + .single(); + + if (budgetError && budgetError.code !== 'PGRST116') throw budgetError; + + // 카테고리 예산 가져오기 + const { data: categoryData, error: categoryError } = await supabase + .from('category_budgets') + .select('*') + .eq('user_id', userId); + + if (categoryError) throw categoryError; + + if (budgetData) { + // 예산 데이터 로컬 형식으로 변환 + const localBudgetData = { + daily: { + targetAmount: budgetData.daily_target, + spentAmount: 0, // 지출액은 로컬에서 계산 + remainingAmount: budgetData.daily_target + }, + weekly: { + targetAmount: budgetData.weekly_target, + spentAmount: 0, + remainingAmount: budgetData.weekly_target + }, + monthly: { + targetAmount: budgetData.monthly_target, + spentAmount: 0, + remainingAmount: budgetData.monthly_target + } + }; + + localStorage.setItem('budgetData', JSON.stringify(localBudgetData)); + } + + if (categoryData && categoryData.length > 0) { + // 카테고리 예산 로컬 형식으로 변환 + const localCategoryBudgets = categoryData.reduce((acc, curr) => { + acc[curr.category] = curr.amount; + return acc; + }, {} as Record); + + localStorage.setItem('categoryBudgets', JSON.stringify(localCategoryBudgets)); + } + + console.log('예산 데이터 다운로드 완료'); + } catch (error) { + console.error('예산 데이터 다운로드 실패:', error); + } +}; diff --git a/src/utils/sync/syncSettings.ts b/src/utils/sync/syncSettings.ts new file mode 100644 index 0000000..f9de300 --- /dev/null +++ b/src/utils/sync/syncSettings.ts @@ -0,0 +1,16 @@ + +// Core synchronization settings utilities + +/** + * Check if synchronization is enabled in local storage + */ +export const isSyncEnabled = (): boolean => { + return localStorage.getItem('syncEnabled') === 'true'; +}; + +/** + * Update synchronization settings in local storage + */ +export const setSyncEnabled = (enabled: boolean): void => { + localStorage.setItem('syncEnabled', enabled.toString()); +}; diff --git a/src/utils/sync/transactionSync.ts b/src/utils/sync/transactionSync.ts new file mode 100644 index 0000000..e132603 --- /dev/null +++ b/src/utils/sync/transactionSync.ts @@ -0,0 +1,76 @@ + +import { supabase } from '@/lib/supabase'; +import { Transaction } from '@/components/TransactionCard'; +import { isSyncEnabled } from './syncSettings'; + +/** + * Upload transaction data from local storage to Supabase + */ +export const uploadTransactions = async (userId: string): Promise => { + if (!isSyncEnabled()) return; + + try { + const localTransactions = localStorage.getItem('transactions'); + if (!localTransactions) return; + + const transactions: Transaction[] = JSON.parse(localTransactions); + + // 기존 데이터 삭제 후 새로 업로드 + await supabase + .from('transactions') + .delete() + .eq('user_id', userId); + + // 트랜잭션 배치 처리 + const { error } = await supabase.from('transactions').insert( + transactions.map(t => ({ + user_id: userId, + title: t.title, + amount: t.amount, + date: t.date, + category: t.category, + type: t.type, + transaction_id: t.id // 로컬 ID 보존 + })) + ); + + if (error) throw error; + + console.log('트랜잭션 업로드 완료'); + } catch (error) { + console.error('트랜잭션 업로드 실패:', error); + } +}; + +/** + * Download transaction data from Supabase to local storage + */ +export const downloadTransactions = async (userId: string): Promise => { + if (!isSyncEnabled()) return; + + try { + const { data, error } = await supabase + .from('transactions') + .select('*') + .eq('user_id', userId); + + if (error) throw error; + + if (data && data.length > 0) { + // Supabase 형식에서 로컬 형식으로 변환 + const transactions = data.map(t => ({ + id: t.transaction_id || t.id, + title: t.title, + amount: t.amount, + date: t.date, + category: t.category, + type: t.type + })); + + localStorage.setItem('transactions', JSON.stringify(transactions)); + console.log('트랜잭션 다운로드 완료'); + } + } catch (error) { + console.error('트랜잭션 다운로드 실패:', error); + } +}; diff --git a/src/utils/syncUtils.ts b/src/utils/syncUtils.ts index f61dfef..5ecc153 100644 --- a/src/utils/syncUtils.ts +++ b/src/utils/syncUtils.ts @@ -1,206 +1,21 @@ -import { supabase } from '@/lib/supabase'; -import { Transaction } from '@/components/TransactionCard'; +import { isSyncEnabled, setSyncEnabled } from './sync/syncSettings'; +import { uploadTransactions, downloadTransactions } from './sync/transactionSync'; +import { uploadBudgets, downloadBudgets } from './sync/budgetSync'; -// 동기화 상태 확인 -export const isSyncEnabled = (): boolean => { - return localStorage.getItem('syncEnabled') === 'true'; +// Export all utility functions to maintain the same public API +export { + isSyncEnabled, + setSyncEnabled, + uploadTransactions, + downloadTransactions, + uploadBudgets, + downloadBudgets }; -// 동기화 설정 변경 -export const setSyncEnabled = (enabled: boolean): void => { - localStorage.setItem('syncEnabled', enabled.toString()); -}; - -// 로컬 트랜잭션 데이터를 Supabase에 업로드 -export const uploadTransactions = async (userId: string): Promise => { - if (!isSyncEnabled()) return; - - try { - const localTransactions = localStorage.getItem('transactions'); - if (!localTransactions) return; - - const transactions: Transaction[] = JSON.parse(localTransactions); - - // 기존 데이터 삭제 후 새로 업로드 - await supabase - .from('transactions') - .delete() - .eq('user_id', userId); - - // 트랜잭션 배치 처리 - const { error } = await supabase.from('transactions').insert( - transactions.map(t => ({ - user_id: userId, - title: t.title, - amount: t.amount, - date: t.date, - category: t.category, - type: t.type, - transaction_id: t.id // 로컬 ID 보존 - })) - ); - - if (error) throw error; - - console.log('트랜잭션 업로드 완료'); - } catch (error) { - console.error('트랜잭션 업로드 실패:', error); - } -}; - -// Supabase에서 트랜잭션 데이터 다운로드 -export const downloadTransactions = async (userId: string): Promise => { - if (!isSyncEnabled()) return; - - try { - const { data, error } = await supabase - .from('transactions') - .select('*') - .eq('user_id', userId); - - if (error) throw error; - - if (data && data.length > 0) { - // Supabase 형식에서 로컬 형식으로 변환 - const transactions = data.map(t => ({ - id: t.transaction_id || t.id, - title: t.title, - amount: t.amount, - date: t.date, - category: t.category, - type: t.type - })); - - localStorage.setItem('transactions', JSON.stringify(transactions)); - console.log('트랜잭션 다운로드 완료'); - } - } catch (error) { - console.error('트랜잭션 다운로드 실패:', error); - } -}; - -// 예산 데이터 업로드 -export const uploadBudgets = async (userId: string): Promise => { - if (!isSyncEnabled()) return; - - try { - const budgetData = localStorage.getItem('budgetData'); - const categoryBudgets = localStorage.getItem('categoryBudgets'); - - if (budgetData) { - const parsedBudgetData = JSON.parse(budgetData); - - // 기존 예산 데이터 삭제 - await supabase - .from('budgets') - .delete() - .eq('user_id', userId); - - // 새 예산 데이터 삽입 - const { error } = await supabase.from('budgets').insert({ - user_id: userId, - daily_target: parsedBudgetData.daily.targetAmount, - weekly_target: parsedBudgetData.weekly.targetAmount, - monthly_target: parsedBudgetData.monthly.targetAmount - }); - - if (error) throw error; - } - - if (categoryBudgets) { - const parsedCategoryBudgets = JSON.parse(categoryBudgets); - - // 기존 카테고리 예산 삭제 - await supabase - .from('category_budgets') - .delete() - .eq('user_id', userId); - - // 카테고리별 예산 데이터 변환 및 삽입 - const categoryEntries = Object.entries(parsedCategoryBudgets).map( - ([category, amount]) => ({ - user_id: userId, - category, - amount - }) - ); - - const { error } = await supabase - .from('category_budgets') - .insert(categoryEntries); - - if (error) throw error; - } - - console.log('예산 데이터 업로드 완료'); - } catch (error) { - console.error('예산 데이터 업로드 실패:', error); - } -}; - -// 예산 데이터 다운로드 -export const downloadBudgets = async (userId: string): Promise => { - if (!isSyncEnabled()) return; - - try { - // 예산 데이터 가져오기 - const { data: budgetData, error: budgetError } = await supabase - .from('budgets') - .select('*') - .eq('user_id', userId) - .single(); - - if (budgetError && budgetError.code !== 'PGRST116') throw budgetError; - - // 카테고리 예산 가져오기 - const { data: categoryData, error: categoryError } = await supabase - .from('category_budgets') - .select('*') - .eq('user_id', userId); - - if (categoryError) throw categoryError; - - if (budgetData) { - // 예산 데이터 로컬 형식으로 변환 - const localBudgetData = { - daily: { - targetAmount: budgetData.daily_target, - spentAmount: 0, // 지출액은 로컬에서 계산 - remainingAmount: budgetData.daily_target - }, - weekly: { - targetAmount: budgetData.weekly_target, - spentAmount: 0, - remainingAmount: budgetData.weekly_target - }, - monthly: { - targetAmount: budgetData.monthly_target, - spentAmount: 0, - remainingAmount: budgetData.monthly_target - } - }; - - localStorage.setItem('budgetData', JSON.stringify(localBudgetData)); - } - - if (categoryData && categoryData.length > 0) { - // 카테고리 예산 로컬 형식으로 변환 - const localCategoryBudgets = categoryData.reduce((acc, curr) => { - acc[curr.category] = curr.amount; - return acc; - }, {} as Record); - - localStorage.setItem('categoryBudgets', JSON.stringify(localCategoryBudgets)); - } - - console.log('예산 데이터 다운로드 완료'); - } catch (error) { - console.error('예산 데이터 다운로드 실패:', error); - } -}; - -// 전체 데이터 동기화 +/** + * Synchronize all data with Supabase + */ export const syncAllData = async (userId: string): Promise => { if (!userId || !isSyncEnabled()) return;