Remove offline mode option

This commit removes the offline mode functionality and focuses on resolving server-side issues.
This commit is contained in:
gpt-engineer-app[bot]
2025-03-15 13:20:51 +00:00
parent 4f8b1c0189
commit 5853e5f51b
4 changed files with 145 additions and 50 deletions

View File

@@ -9,9 +9,15 @@ export const showAuthToast = (title: string, description: string, variant: 'defa
// 에러 메시지 처리 유틸리티 함수 // 에러 메시지 처리 유틸리티 함수
export const handleNetworkError = (error: any): string => { export const handleNetworkError = (error: any): string => {
return error.message && error.message.includes('fetch') if (error.message && error.message.includes('fetch')) {
? '서버 연결에 실패했습니다. 네트워크 연결을 확인해주세요.' return '서버 연결에 실패했습니다. 네트워크 연결을 확인해주세요.';
: (error.message || '예상치 못한 오류가 발생했습니다.'); } else if (error.message && error.message.includes('CORS')) {
return 'CORS 오류가 발생했습니다. 서버 설정 또는 CORS 프록시를 확인하세요.';
} else if (error.message && error.message.includes('NetworkError')) {
return '네트워크 오류가 발생했습니다. 인터넷 연결을 확인하세요.';
}
return error.message || '예상치 못한 오류가 발생했습니다.';
}; };
// 응답 파싱 유틸리티 함수 // 응답 파싱 유틸리티 함수
@@ -60,23 +66,98 @@ export const hasCorsIssue = (error: any): boolean => {
); );
}; };
// 오프라인 모드 확인 // Supabase 연결 상태 확인
export const isOfflineMode = (): boolean => { export const checkSupabaseConnection = async (): Promise<boolean> => {
return !navigator.onLine || localStorage.getItem('offline_mode') === 'true'; try {
const { data, error } = await supabase.auth.getSession();
// 오류가 없으면 연결 성공
if (!error) {
return true;
}
// 오류 메시지 확인
if (error.message && (
error.message.includes('Failed to fetch') ||
error.message.includes('Network') ||
error.message.includes('CORS')
)) {
return false;
}
// 다른 오류는 연결은 됐지만 세션/인증 관련 오류이므로 연결은 성공
return true;
} catch (err) {
console.error('Supabase 연결 확인 중 오류:', err);
return false;
}
}; };
// 데모 모드 사용자 생성 (오프라인 환경용) // 서버 연결 상태 검사
export const createDemoUser = (email: string, username: string) => { export const verifyServerConnection = async (): Promise<{
// 데모용 가상 사용자 정보 connected: boolean;
const demoUser = { message: string;
id: 'demo-' + Date.now(), }> => {
email, try {
user_metadata: { username }, const start = Date.now();
created_at: new Date().toISOString()
}; // Supabase URL 가져오기
const supabaseUrl = localStorage.getItem('supabase_url') || 'http://a11.ism.kr:8000';
// 로컬 스토리지에 저장
localStorage.setItem('demo_user', JSON.stringify(demoUser)); // 단순 헬스 체크 요청
const response = await fetch(`${supabaseUrl}/rest/v1/`, {
return demoUser; method: 'GET',
headers: {
'Content-Type': 'application/json'
}
});
const elapsed = Date.now() - start;
if (response.ok || response.status === 401) {
// 401도 서버가 응답했다는 의미이므로 연결 성공으로 간주
return {
connected: true,
message: `서버 연결 성공 (응답 시간: ${elapsed}ms)`
};
} else {
return {
connected: false,
message: `서버 응답 오류: ${response.status} ${response.statusText}`
};
}
} catch (error: any) {
console.error('서버 연결 확인 중 오류:', error);
// 오류 유형에 따른 메시지 설정
let errorMessage = '알 수 없는 네트워크 오류';
if (error.message) {
if (error.message.includes('Failed to fetch')) {
errorMessage = 'CORS 정책 오류 또는 서버 연결 실패';
} else if (error.message.includes('NetworkError')) {
errorMessage = '네트워크 연결 실패';
} else if (error.message.includes('TypeError')) {
errorMessage = '네트워크 요청 형식 오류';
} else {
errorMessage = error.message;
}
}
return {
connected: false,
message: errorMessage
};
}
};
// 서버 URL 검증
export const validateServerUrl = (url: string): boolean => {
try {
// URL 유효성 검사
new URL(url);
return true;
} catch (e) {
return false;
}
}; };

View File

@@ -1,18 +1,17 @@
import { supabase } from '@/lib/supabase'; import { supabase } from '@/lib/supabase';
import { handleNetworkError, parseResponse, showAuthToast, isOfflineMode, createDemoUser } from './auth.utils'; import { handleNetworkError, parseResponse, showAuthToast, verifyServerConnection } from './auth.utils';
export const signIn = async (email: string, password: string) => { export const signIn = async (email: string, password: string) => {
try { try {
// 오프라인 모드 확인 // 서버 연결 상태 먼저 확인
if (isOfflineMode()) { const connectionStatus = await verifyServerConnection();
console.log('오프라인 모드로 로그인 시도:', email); if (!connectionStatus.connected) {
showAuthToast('서버 연결 실패', connectionStatus.message, 'destructive');
// 데모 사용자 생성 (데모 모드용) return {
const demoUser = createDemoUser(email, email.split('@')[0]); error: { message: `서버 연결에 실패했습니다: ${connectionStatus.message}` },
user: null
showAuthToast('로그인 성공', '오프라인 모드로 로그인되었습니다.'); };
return { error: null, user: demoUser };
} }
console.log('로그인 시도 중:', email); console.log('로그인 시도 중:', email);

View File

@@ -1,23 +1,12 @@
import { supabase } from '@/lib/supabase'; import { supabase } from '@/lib/supabase';
import { handleNetworkError, showAuthToast, isOfflineMode, createDemoUser } from './auth.utils'; import { handleNetworkError, showAuthToast } from './auth.utils';
export const signUp = async (email: string, password: string, username: string) => { export const signUp = async (email: string, password: string, username: string) => {
try { try {
// 오프라인 모드 확인
if (isOfflineMode()) {
console.log('오프라인 모드로 회원가입 시도:', { email, username });
// 데모 사용자 생성
const demoUser = createDemoUser(email, username);
showAuthToast('회원가입 성공', '오프라인 모드로 회원가입되었습니다.');
return { error: null, user: demoUser };
}
console.log('회원가입 시도:', { email, username }); console.log('회원가입 시도:', { email, username });
// 기본 회원가입 시도 // 회원가입 시도
const { data, error } = await supabase.auth.signUp({ const { data, error } = await supabase.auth.signUp({
email, email,
password, password,
@@ -44,14 +33,17 @@ export const signUp = async (email: string, password: string, username: string)
errorMessage = '서버 연결 문제: 이메일 검증에 실패했습니다.'; errorMessage = '서버 연결 문제: 이메일 검증에 실패했습니다.';
} else if (error.message.includes('json')) { } else if (error.message.includes('json')) {
errorMessage = '서버 응답 처리 오류: 네트워크 연결을 확인하세요.'; errorMessage = '서버 응답 처리 오류: 네트워크 연결을 확인하세요.';
} else if (error.message.includes('fetch failed')) {
errorMessage = '서버 연결에 실패했습니다. 네트워크 연결 또는 서버 상태를 확인하세요.';
} else if (error.message.includes('Failed to fetch')) {
errorMessage = 'CORS 오류가 발생했습니다. 서버 설정을 확인하거나 네트워크 관리자에게 문의하세요.';
} }
showAuthToast('회원가입 실패', errorMessage, 'destructive'); showAuthToast('회원가입 실패', errorMessage, 'destructive');
return { error, user: null }; return { error, user: null };
} }
// 즉시 로그인이 필요한 경우 여기서 처리 // 성공 메시지 표시
// 기본적으로는 이메일 확인 요청
showAuthToast('회원가입 성공', '이메일 확인 후 로그인해주세요.'); showAuthToast('회원가입 성공', '이메일 확인 후 로그인해주세요.');
// 개발 환경 또는 데모 모드에서는 즉시 로그인 허용 // 개발 환경 또는 데모 모드에서는 즉시 로그인 허용

View File

@@ -1,3 +1,4 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Link, useNavigate } from "react-router-dom"; import { Link, useNavigate } from "react-router-dom";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
@@ -6,6 +7,8 @@ import { Button } from "@/components/ui/button";
import { ArrowRight, Mail, KeyRound, User, Eye, EyeOff } from "lucide-react"; import { ArrowRight, Mail, KeyRound, User, Eye, EyeOff } from "lucide-react";
import { useToast } from "@/hooks/useToast.wrapper"; import { useToast } from "@/hooks/useToast.wrapper";
import { useAuth } from "@/contexts/auth"; import { useAuth } from "@/contexts/auth";
import TestConnectionSection from "@/components/auth/TestConnectionSection";
import SupabaseConnectionStatus from "@/components/auth/SupabaseConnectionStatus";
const Register = () => { const Register = () => {
const [username, setUsername] = useState(""); const [username, setUsername] = useState("");
@@ -14,6 +17,8 @@ const Register = () => {
const [confirmPassword, setConfirmPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState("");
const [showPassword, setShowPassword] = useState(false); const [showPassword, setShowPassword] = useState(false);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [registerError, setRegisterError] = useState<string | null>(null);
const [testResults, setTestResults] = useState<any>(null);
const { toast } = useToast(); const { toast } = useToast();
const navigate = useNavigate(); const navigate = useNavigate();
const { signUp, user } = useAuth(); const { signUp, user } = useAuth();
@@ -27,6 +32,7 @@ const Register = () => {
const handleRegister = async (e: React.FormEvent) => { const handleRegister = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
setRegisterError(null);
if (!username || !email || !password || !confirmPassword) { if (!username || !email || !password || !confirmPassword) {
toast({ toast({
@@ -51,12 +57,15 @@ const Register = () => {
try { try {
const { error, user } = await signUp(email, password, username); const { error, user } = await signUp(email, password, username);
if (!error && user) { if (error) {
// 데모 모드에서는 즉시 메인 페이지로 이동 setRegisterError(error.message || '알 수 없는 오류가 발생했습니다.');
navigate("/"); } else if (user) {
// 회원가입 성공 시 로그인 페이지로 이동
navigate("/login");
} }
} catch (error) { } catch (error: any) {
console.error("회원가입 처리 중 예외 발생:", error); console.error("회원가입 처리 중 예외 발생:", error);
setRegisterError(error.message || '예상치 못한 오류가 발생했습니다.');
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }
@@ -140,6 +149,12 @@ const Register = () => {
</div> </div>
</div> </div>
{registerError && (
<div className="p-3 bg-red-50 border border-red-200 rounded-md text-red-700 text-sm">
<p>{registerError}</p>
</div>
)}
<Button <Button
type="submit" type="submit"
className="w-full bg-neuro-income hover:bg-neuro-income/80 text-white py-6 h-auto" className="w-full bg-neuro-income hover:bg-neuro-income/80 text-white py-6 h-auto"
@@ -151,7 +166,7 @@ const Register = () => {
</form> </form>
</div> </div>
<div className="text-center"> <div className="text-center mb-4">
<p className="text-gray-500"> <p className="text-gray-500">
?{" "} ?{" "}
<Link to="/login" className="text-neuro-income font-medium hover:underline"> <Link to="/login" className="text-neuro-income font-medium hover:underline">
@@ -159,6 +174,14 @@ const Register = () => {
</Link> </Link>
</p> </p>
</div> </div>
{/* Supabase 연결 테스트 섹션 */}
<TestConnectionSection
setLoginError={setRegisterError}
setTestResults={setTestResults}
/>
<SupabaseConnectionStatus testResults={testResults} />
</div> </div>
</div> </div>
); );