Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions apps/native/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as SplashScreen from 'expo-splash-screen';
import { useEffect, useState } from 'react';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useAuthStore } from '../src/stores/authStore';
import { useAuthStore, initializeAuth } from '../src/stores/authStore';

SplashScreen.preventAutoHideAsync();

Expand All @@ -16,11 +16,16 @@ const AppLayout = () => {
const segments = useSegments();

useEffect(() => {
// 앱 초기화
setTimeout(() => {
setIsReady(true);
SplashScreen.hideAsync();
}, 1000);
// 앱 초기화 및 자동 로그인
const init = async () => {
await initializeAuth(); // 저장된 refresh token으로 자동 로그인
setTimeout(() => {
setIsReady(true);
SplashScreen.hideAsync();
}, 1000);
};

init();
}, []);

// 라우팅 로직
Expand Down
71 changes: 70 additions & 1 deletion apps/web/app/(view)/(main)/microorganismTest/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,72 @@
'use client';

export default function MicroorganismTestPage() {
return <div>MicroorganismTestPage</div>;
return (
<div style={{
minHeight: '100vh',
backgroundColor: '#fff',
display: 'flex',
flexDirection: 'column'
}}>
{/* 헤더 */}
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: '16px 20px',
paddingTop: 'calc(16px + env(safe-area-inset-top))',
borderBottom: '1px solid #f0f0f0',
}}>
<h1 style={{
fontSize: '16px',
fontWeight: '600',
margin: 0,
color: '#000',
}}>
미생물 검사
</h1>
</div>

{/* 메인 컨텐츠 */}
<div style={{
flex: 1,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
padding: '40px 20px',
}}>
{/* 아이콘 */}
<div style={{
fontSize: '80px',
marginBottom: '24px',
}}>
🔬
</div>

{/* 타이틀 */}
<h2 style={{
fontSize: '24px',
fontWeight: '700',
color: '#333',
marginBottom: '12px',
}}>
서비스 준비중입니다
</h2>

{/* 설명 */}
<p style={{
fontSize: '14px',
color: '#666',
textAlign: 'center',
lineHeight: '1.6',
maxWidth: '280px',
}}>
더 나은 서비스를 제공하기 위해<br />
열심히 준비하고 있습니다.<br />
조금만 기다려주세요!
</p>
</div>
</div>
);
}
19 changes: 13 additions & 6 deletions packages/shared/src/apis/interceptors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,26 @@ export const errorInterceptor = async (error: AxiosError<ErrorResponse>): Promis
if (status === 401) {
if (errorCode === 'TOKEN_EXPIRED') {
// Access Token 만료 - Refresh Token으로 재발급 시도
const isRefreshRequest = config.url?.includes('/auth/refresh');
const isRefreshRequest = config.url?.includes('/jwt/refresh');

if (isRefreshRequest) {
return handleLogout('TOKEN_EXPIRED', '세션이 만료되었습니다. 다시 로그인해주세요.');
}

try {
const baseURL = config.baseURL || '';
const refreshUrl = baseURL.endsWith('/') ? 'auth/refresh' : '/auth/refresh';

const response = await axios.get(`${baseURL}${refreshUrl}`, {
withCredentials: true,
});
const refreshUrl = baseURL.endsWith('/') ? 'jwt/refresh' : '/jwt/refresh';

// 네이티브에서는 저장된 refresh token 사용
const { getRefreshToken } = await import('../stores/authStore');
const refreshToken = await getRefreshToken();

const response = await axios.post(`${baseURL}${refreshUrl}`,
refreshToken ? { refreshToken } : {}, // 네이티브: body에 포함, 웹: 쿠키로 전송
{
withCredentials: true, // 웹의 경우 쿠키 전송
}
);
const newAccessToken = response.data.accessToken;

await useAuthStore.getState().setAccessToken(newAccessToken);
Expand Down