diff --git a/src/App.tsx b/src/App.tsx index 3db35b9..7138416 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,175 +1,106 @@ -import { Toaster } from "@/components/ui/toaster"; -import { Toaster as Sonner } from "@/components/ui/sonner"; -import { TooltipProvider } from "@/components/ui/tooltip"; -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { BrowserRouter, Routes, Route } from "react-router-dom"; -import { useState, useEffect } from "react"; -import Index from "./pages/Index"; -import Transactions from "./pages/Transactions"; -import Analytics from "./pages/Analytics"; -import Settings from "./pages/Settings"; -import ProfileManagement from "./pages/ProfileManagement"; -import NotificationSettings from "./pages/NotificationSettings"; -import SecurityPrivacySettings from "./pages/SecurityPrivacySettings"; -import HelpSupport from "./pages/HelpSupport"; -import PaymentMethods from "./pages/PaymentMethods"; -import NotFound from "./pages/NotFound"; -import Login from "./pages/Login"; -import Register from "./pages/Register"; -import ForgotPassword from "./pages/ForgotPassword"; -import SupabaseSettings from "./pages/SupabaseSettings"; -import { initSyncSettings } from "./utils/syncUtils"; -import { AuthProvider } from "./contexts/auth"; -import { BudgetProvider } from "./contexts/BudgetContext"; +import React from 'react'; +import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; +import './App.css'; +import Login from './pages/Login'; +import Register from './pages/Register'; +import NotFound from './pages/NotFound'; +import NavBar from './components/NavBar'; +import Index from './pages/Index'; +import AuthContextWrapper from './contexts/AuthContext'; +import { Toaster } from './components/ui/toaster'; +import ProfileManagement from './pages/ProfileManagement'; +import SupabaseSettings from './pages/SupabaseSettings'; +import Transactions from './pages/Transactions'; +import SecurityPrivacySettings from './pages/SecurityPrivacySettings'; +import NotificationSettings from './pages/NotificationSettings'; +import HelpSupport from './pages/HelpSupport'; +import ForgotPassword from './pages/ForgotPassword'; +import Analytics from './pages/Analytics'; +import PaymentMethods from './pages/PaymentMethods'; +import Settings from './pages/Settings'; -// 전역 오류 처리 +// 전역 오류 핸들러 const handleError = (error: any) => { - console.error("앱 오류 발생:", error); + console.error('앱 오류 발생:', error); }; -// 오류 발생 시 전역 핸들러에 연결 -window.addEventListener('error', (event) => { - handleError(event.error); -}); - -window.addEventListener('unhandledrejection', (event) => { - handleError(event.reason); -}); - -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - retry: 1, - refetchOnWindowFocus: false, - meta: { - // meta 객체를 사용하여 오류 관리 - errorHandler: (error: Error) => { - console.error("쿼리 오류:", error); - } - } - }, - mutations: { - // onSettled를 사용하여 완료 시 호출되는 콜백 설정 - onSettled: (_data, error) => { - if (error) { - console.error("뮤테이션 오류:", error); - } - } - } - }, -}); - -const App = () => { - const [isLoaded, setIsLoaded] = useState(false); - const [initError, setInitError] = useState(null); - - useEffect(() => { - // 애플리케이션 초기화 및 로딩 상태 관리 - try { - // 동기화 설정 초기화 - initSyncSettings(); - - // 기본 예산 데이터 초기화 - if (!localStorage.getItem('budgetData')) { - const defaultBudgetData = { - daily: { - targetAmount: 40000, - spentAmount: 0, - remainingAmount: 40000 - }, - weekly: { - targetAmount: 280000, - spentAmount: 0, - remainingAmount: 280000 - }, - monthly: { - targetAmount: 1200000, - spentAmount: 0, - remainingAmount: 1200000 - } - }; - localStorage.setItem('budgetData', JSON.stringify(defaultBudgetData)); - } - - // 기본 카테고리 예산 설정 - if (!localStorage.getItem('categoryBudgets')) { - const defaultCategoryBudgets = { - 식비: 400000, - 생활비: 600000, - 교통비: 200000 - }; - localStorage.setItem('categoryBudgets', JSON.stringify(defaultCategoryBudgets)); - } - - // 빈 트랜잭션 배열 초기화 - if (!localStorage.getItem('transactions')) { - localStorage.setItem('transactions', JSON.stringify([])); - } - - setIsLoaded(true); - } catch (error) { - console.error('앱 초기화 중 오류 발생:', error); - setInitError(error instanceof Error ? error : new Error('앱 초기화 중 알 수 없는 오류가 발생했습니다')); - // 오류가 발생해도 앱 로딩 - setIsLoaded(true); - } - }, []); - - if (!isLoaded) { - return
-
-
-

앱을 로딩 중입니다...

-
-
; +// 오류 경계 컴포넌트 +class ErrorBoundary extends React.Component< + { children: React.ReactNode }, + { hasError: boolean; error: Error | null } +> { + constructor(props: { children: React.ReactNode }) { + super(props); + this.state = { hasError: false, error: null }; } - if (initError) { - return
-
-

앱 로드 오류

-

{initError.message}

- -
-
; + static getDerivedStateFromError(error: Error) { + return { hasError: true, error }; } + componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { + handleError({ error, errorInfo }); + } + + render() { + if (this.state.hasError) { + return ( +
+
+

오류가 발생했습니다

+

+ 앱에서 예상치 못한 오류가 발생했습니다. 페이지를 새로고침하거나 나중에 다시 시도해주세요. +

+
+              {this.state.error?.message}
+            
+ +
+
+ ); + } + + return this.props.children; + } +} + +function App() { return ( - - - - - - - + + + +
+ +
} /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> } /> } /> - } /> + } /> + } /> } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> } /> - - - - - +
+ +
+
+
+
); -}; +} export default App; diff --git a/src/contexts/AuthContext.tsx b/src/contexts/AuthContext.tsx index 6426970..4c481a9 100644 --- a/src/contexts/AuthContext.tsx +++ b/src/contexts/AuthContext.tsx @@ -1,4 +1,9 @@ -import { AuthProvider, useAuth } from '@/contexts/auth'; +import React from 'react'; +import { AuthProvider, useAuth } from './auth/AuthProvider'; export { AuthProvider, useAuth }; + +export default function AuthContextWrapper({ children }: { children: React.ReactNode }) { + return {children}; +} diff --git a/src/contexts/auth/signIn.ts b/src/contexts/auth/signIn.ts index fef1fad..e04fb0e 100644 --- a/src/contexts/auth/signIn.ts +++ b/src/contexts/auth/signIn.ts @@ -1,4 +1,5 @@ -import { supabase } from '@/lib/supabase'; + +import { supabase } from '@/integrations/supabase/client'; import { handleNetworkError, parseResponse, @@ -10,66 +11,34 @@ import { getProxyType, isCorsProxyEnabled } from '@/lib/supabase/config'; export const signIn = async (email: string, password: string) => { try { - // 서버 연결 상태 먼저 확인 - const connectionStatus = await verifyServerConnection(); - if (!connectionStatus.connected) { - console.log('서버 연결 실패:', connectionStatus.message); - - // 프록시 설정 확인 및 추천 - const usingProxy = isCorsProxyEnabled(); - const proxyType = getProxyType(); - let errorMessage = connectionStatus.message; - - if (!usingProxy) { - errorMessage = `${errorMessage} (설정에서 Cloudflare CORS 프록시 활성화를 권장합니다)`; - } else if (proxyType !== 'cloudflare') { - errorMessage = `${errorMessage} (설정에서 Cloudflare CORS 프록시로 변경을 권장합니다)`; - } - - showAuthToast('서버 연결 실패', errorMessage, 'destructive'); - return { - error: { message: `서버 연결에 실패했습니다: ${errorMessage}` }, - user: null - }; - } - console.log('로그인 시도 중:', email); - // 직접 API 호출 방식 시도 + // 기본 Supabase 인증 방식 시도 try { - return await signInWithDirectApi(email, password); - } catch (directApiError: any) { - console.error('직접 API 호출 방식 실패:', directApiError); + const { data, error } = await supabase.auth.signInWithPassword({ + email, + password + }); - // 기본 Supabase 인증 방식 시도 - try { - const { data, error } = await supabase.auth.signInWithPassword({ - email, - password - }); + if (!error && data.user) { + showAuthToast('로그인 성공', '환영합니다!'); + return { error: null, user: data.user }; + } else if (error) { + console.error('Supabase 기본 로그인 오류:', error.message); - if (!error && data.user) { - showAuthToast('로그인 성공', '환영합니다!'); - return { error: null, user: data.user }; - } else if (error) { - console.error('Supabase 기본 로그인 오류:', error.message); - - let errorMessage = error.message; - if (error.message.includes('Invalid login credentials')) { - errorMessage = '이메일 또는 비밀번호가 올바르지 않습니다.'; - } else if (error.message.includes('Email not confirmed')) { - errorMessage = '이메일 인증이 완료되지 않았습니다. 이메일을 확인해주세요.'; - } - - showAuthToast('로그인 실패', errorMessage, 'destructive'); - return { error: { message: errorMessage }, user: null }; + let errorMessage = error.message; + if (error.message.includes('Invalid login credentials')) { + errorMessage = '이메일 또는 비밀번호가 올바르지 않습니다.'; + } else if (error.message.includes('Email not confirmed')) { + errorMessage = '이메일 인증이 완료되지 않았습니다. 이메일을 확인해주세요.'; } - } catch (basicAuthError: any) { - console.warn('Supabase 기본 인증 방식 예외 발생:', basicAuthError); - // 오류 전파 - throw directApiError; + showAuthToast('로그인 실패', errorMessage, 'destructive'); + return { error: { message: errorMessage }, user: null }; } + } catch (basicAuthError: any) { + console.warn('Supabase 기본 인증 방식 예외 발생:', basicAuthError); + throw basicAuthError; } // 여기까지 왔다면 모든 로그인 시도가 실패한 것